集成测试中 MockMvc 和 RestTemplate 的区别
Posted
技术标签:
【中文标题】集成测试中 MockMvc 和 RestTemplate 的区别【英文标题】:Difference between MockMvc and RestTemplate in integration tests 【发布时间】:2014-11-12 03:55:31 【问题描述】:MockMvc 和 RestTemplate 都用于与 Spring 和 JUnit 的集成测试。
问题是:它们之间有什么区别,我们什么时候应该选择一个而不是另一个?
这只是两个选项的示例:
//MockMVC example
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
(...)
//RestTemplate example
ResponseEntity<User> entity = restTemplate.exchange("/api/users",
HttpMethod.GET,
new HttpEntity<String>(...),
User.class);
assertEquals(HttpStatus.OK, entity.getStatusCode());
【问题讨论】:
【参考方案1】:使用MockMvc
,您通常会设置整个 Web 应用程序上下文并模拟 HTTP 请求和响应。因此,尽管一个假的DispatcherServlet
已启动并运行,模拟您的 MVC 堆栈将如何运行,但并没有建立真正的网络连接。
使用RestTemplate
,您必须部署一个实际的服务器实例来侦听您发送的 HTTP 请求。
【讨论】:
【参考方案2】:如this中所说
当你想测试应用程序的服务器端时,你应该使用MockMvc
的文章:
Spring MVC 测试建立在来自
spring-test
的模拟请求和响应之上,并且不需要正在运行的 servlet 容器。主要区别在于实际的 Spring MVC 配置是通过 TestContext 框架加载的,并且请求是通过实际调用DispatcherServlet
以及在运行时使用的所有相同的 Spring MVC 基础结构来执行的。
例如:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("servlet-context.xml")
public class SampleTests
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup()
this.mockMvc = webAppContextSetup(this.wac).build();
@Test
public void getFoo() throws Exception
this.mockMvc.perform(get("/foo").accept("application/json"))
.andExpect(status().isOk())
.andExpect(content().mimeType("application/json"))
.andExpect(jsonPath("$.name").value("Lee"));
当你想测试 Rest Client-side 应用程序时应该使用 RestTemplate
:
如果您有使用
RestTemplate
的代码,您可能需要对其进行测试,并且可以针对正在运行的服务器或模拟 RestTemplate。客户端 REST 测试支持提供了第三种选择,即使用实际的RestTemplate
,但使用自定义的ClientHttpRequestFactory
对其进行配置,该ClientHttpRequestFactory
会根据实际请求检查预期并返回存根响应。
示例:
RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
mockServer.expect(requestTo("/greeting"))
.andRespond(withSuccess("Hello world", "text/plain"));
// use RestTemplate ...
mockServer.verify();
另请阅读this example
【讨论】:
您在哪里准备名称为Lee
的模拟实体?我认为andExpect(jsonPath("$.name").value("Lee"))
验证会失败。
@naXa,这些是集成测试,所以我们假设相应的数据存储在数据库中或在测试之前填充。 Spring MVC 仅测试“模拟”servlet 容器,但使用真实 bean、数据库连接等构建应用程序上下文。
但是,mockmvc 无法处理存储在文件中的自定义异常(用于测试负面场景)。它捕获了测试用例功能的“抛出异常”。如何在 MockMvc 中处理这个问题?【参考方案3】:
可以同时使用 RestTemplate 和 MockMvc!
如果您有一个单独的客户端,您已经完成了繁琐的 Java 对象到 URL 的映射以及与 Json 之间的转换,并且您希望将其重用于您的 MockMVC 测试,这将非常有用。
这是怎么做的:
@RunWith(SpringRunner.class)
@ActiveProfiles("integration")
@WebMvcTest(ControllerUnderTest.class)
public class MyTestShould
@Autowired
private MockMvc mockMvc;
@Test
public void verify_some_condition() throws Exception
MockMvcClientHttpRequestFactory requestFactory = new MockMvcClientHttpRequestFactory(mockMvc);
RestTemplate restTemplate = new RestTemplate(requestFactory);
ResponseEntity<SomeClass> result = restTemplate.getForEntity("/my/url", SomeClass.class);
[...]
【讨论】:
对于我的用例,我认为这是最好的方法,因为当 HATEOS(特别是)发挥作用时,RestTemplate 使响应的 ORM 映射更加直接。 @fquinner,但它不能回滚,因为它的行为类似于客户端并在不同的线程中运行,无法回滚。然后你需要维护另一个 testDb以上是关于集成测试中 MockMvc 和 RestTemplate 的区别的主要内容,如果未能解决你的问题,请参考以下文章
MockMVC - 如何使用 org.hamcrest.Matcher 在春季安全集成测试中检查 JWT 令牌的内容