【问题标题】:Difference between MockMvc and RestTemplate in integration tests集成测试中 MockMvc 和 RestTemplate 的区别
【发布时间】:2014-11-12 03:55:31
【问题描述】:

MockMvcRestTemplate 都用于与 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());

【问题讨论】:

    标签: java spring spring-mvc junit integration-testing


    【解决方案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
      猜你喜欢
      • 2015-01-01
      • 2023-03-28
      • 1970-01-01
      • 2018-08-14
      • 1970-01-01
      • 1970-01-01
      • 2011-04-09
      • 2011-07-18
      • 1970-01-01
      相关资源
      最近更新 更多