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


98

我是Spring Boot的新手,正在尝试了解SpringBoot中的测试工作原理。我对以下两个代码段之间的区别感到困惑:

程式码片段1:

@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!"));
    }
}

Answers:


89

@SpringBootTest是常规测试注释。如果您要寻找在1.4之前具有相同功能的产品,那就应该使用它。它根本不使用切片,这意味着它将启动整个应用程序上下文,并且根本不自定义组件扫描。

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

阅读文档也可能会对您有所帮助。


非常感谢您的回复!因此,如果我对您的理解正确,那意味着这两个代码段仅测试应用程序的MVC部分。但是tcode代码段1会加载整个应用程序上下文,而代码段2仅扫描控制器。这个对吗?可以将代码片段1视为测试控制器的单元测试吗?
Revansha '16

1
不,这是不正确的。SpringBootTest正在加载完整的应用程序(在某种程度上,默认情况下,如果有可用的容器,则不会启动嵌入式容器,这就是该容器的webEnvironment用途)。我不会说这@SpringBootTest是控制器的单元测试,但实际上是集成测试。WebMvcTest从某种意义上说,它实际上是对控制器的单元测试,如果它具有依赖关系,则必须自己提供它们(配置或某种模拟)。
史蒂芬·尼科尔

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

4
我不确定我们是否要在这里解决这个问题。也许不安?您似乎经常会想念的是,SpringBootTestWebMvcTest创建的应用程序上下文有很大的不同。前者会加载您的WHOLE应用并启用所有自动配置,而后者仅启用Spring Mvc,但不会进行任何扫描HelloController。毕竟,这取决于您对单元测试的含义。但这就是区别。
Stephane Nicoll

感谢您的答复。这对我很有帮助。现在我了解了为什么我的测试可以与SpringBootTest一起运行,但在WebMvcTest时却例外。再次非常感谢。
Alps1992年

71

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

@WebMvcTest-用于测试控制器层,您需要使用Mock Objects提供所需的其余依赖项。

以下还有更多注释供您参考。

测试应用程序的切片 有时,您想测试应用程序的简单“切片”,而不是自动配置整个应用程序。Spring Boot 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/


这是Sping Boot参考-测试自动配置注释的链接。这里不仅列出了四个@ roshankumar-mutha。入门指南的链接未深入介绍这些内容。
George Pantazes

15

MVC测试旨在仅覆盖应用程序的控制器部分。HTTP请求和响应是模拟的,因此不会创建实际的连接。另一方面,当您使用时@SpringBootTest,将加载Web应用程序上下文的所有配置,并且连接将通过真实的Web服务器。在这种情况下,您不使用 MockMvcbean,而是使用标准RestTemplate(或新的替代方法 TestRestTemplate)。

那么,我们什么时候应该选择一个?@WebMvcTest旨在从服务器端统一测试控制器。@SpringBootTest另一方面,当您要从客户端与应用程序进行交互时,应该将其用于集成测试。

这并不意味着您不能将模拟与@SpringBootTest;一起使用。如果您正在编写集成测试,那仍然有必要。无论如何,最好不要仅将其用于简单控制器的单元测试。

源码-使用Spring Boot学习微服务


4
我不明白为什么要回答这个问题。当您使用时@SpringBootTest,除非您也有webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT(或DEFINED_PORT)并且连接不会通过真实的Web服务器,否则不会启动真实的Web服务器。的默认@SpringBootTest值为WebEnvironment.MOCK
Koray Tugay
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.