使用MockMvc与SpringBootTest和使用WebMvcTest之间的区别

问题描述:

我是Spring Boot的新手,并试图了解如何在SpringBoot中测试。我有点困惑的是以下两个代码段之间的区别:使用MockMvc与SpringBootTest和使用WebMvcTest之间的区别

代码片段:

@RunWith(SpringRunner.class) 
@WebMvcTest(HelloController.class) 
public class HelloControllerApplicationTest { 
    @Autowired  
    private MockMvc mvc; 

    @Test 
    public void getHello() throws Exception { 
     mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON)) 
       .andExpect(status().isOk()) 
       .andExpect(content().string(equalTo("Greetings from Spring Boot!"))); 
    } 
} 

本次测试使用,我相信是有片测试和@WebMvcTest注释仅测试Web应用程序的Mvc层。

代码段2:

@RunWith(SpringRunner.class) 
@SpringBootTest 
@AutoConfigureMockMvc 
public class HelloControllerTest { 

    @Autowired 
    private MockMvc mvc; 

    @Test 
    public void getHello() throws Exception { 
    mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON)) 
      .andExpect(status().isOk()) 
      .andExpect(content().string(equalTo("Greetings from Spring Boot!"))); 
    } 
} 

本试验采用@SpringBootTest注释和MockMvc。那么这和代码片段1有什么不同呢?这有什么不同?

编辑: 添加代码段3(发现这是Spring文档中集成测试的例子)

@RunWith(SpringRunner.class) 
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 
public class HelloControllerIT { 

@LocalServerPort 
private int port; 

private URL base; 

@Autowired 
private TestRestTemplate template; 

@Before 
public void setUp() throws Exception { 
    this.base = new URL("http://localhost:" + port + "/"); 
} 

@Test 
public void getHello() throws Exception { 
    ResponseEntity<String> response = template.getForEntity(base.toString(), 
      String.class); 
    assertThat(response.getBody(), equalTo("Greetings from Spring Boot!")); 
} 
} 

非常好的问题。

@SpringBootTest是一般测试注释。如果你正在寻找在1.4之前做同样事情的东西,那就是你应该使用的东西。它不会使用切片,这意味着它将启动完整的应用程序上下文,并且根本不会自定义组件扫描。

@WebMvcTest只会扫描您定义的控制器和MVC基础结构。而已。因此,如果您的控制器对服务层中的其他bean具有一些依赖性,那么只有在您自己加载配置或为其提供模拟之前,测试才会启动。由于我们只加载应用程序的一小部分,因此速度更快。此注释使用切片。

Reading the doc应该也可以帮助你。

+0

非常感谢响应!。因此,如果我理解正确,那么这意味着这两个代码片段仅测试应用程序的MVC部分。但是tcode代码片段1会加载完整的应用程序上下文,而代码片段2仅会扫描控制器。它是否正确?代码段1是否可以被视为测试控制器的单元测试? – Reshma

+0

不,这是不正确的。 'SpringBootTest'正在加载您的完整应用程序(在某种程度上,默认情况下,如果有可用的,它将不会启动嵌入式容器,这就是'webEnvironment'的用途)。我不会说'@ SpringBootTest'是控制器的单元测试,但更多的是集成测试。 'WebMvcTest'实际上是对你的控制器的单元测试,因为如果它有依赖性,你必须自己提供它们(配置或某种模拟)。 –

+0

再次感谢您的回复。我编辑了这个问题并添加了代码片段3.您提到@SpringBootTest注释更多地用于集成测试。我相信Snippet 3展示了这一点。因此,如果像Snippet 3那样完成集成测试,那么Snippet 2会做什么? Snippet 2使用SpringBootTest注释和一个模拟环境(wenEnvironment属性的默认值)。此外,代码片段3启动嵌入式服务器并进行真正的HTTP调用,而代码段2不执行此操作。所以考虑到这一点,不能将snippet 2视为单元测试? – Reshma

@SpringBootTest注释告诉Spring Boot去找一个主要的配置类(例如一个带有@SpringBootApplication的实例),并用它来启动一个Spring应用程序上下文。 SpringBootTest加载完整的应用程序并注入可能很慢的所有bean。

@WebMvcTest - 用于测试控制器层,您需要提供使用模拟对象所需的其余依赖关系。

以下几个注释供您参考。

测试应用程序 切片有时你想测试应用程序的一个简单的“切片”,而不是自动配置整个应用程序的。春季启动1.4引入了4个新的测试注释:

@WebMvcTest - for testing the controller layer 
@JsonTest - for testing the JSON marshalling and unmarshalling 
@DataJpaTest - for testing the repository layer 
@RestClientTests - for testing REST clients 

参考的详细资料:https://spring.io/guides/gs/testing-web/