Spring Test与JUnit等其他测试框架结合起来,提供了便捷高效的测试手段。而Spring Boot Test 是在Spring Test之上的再次封装,增加了切片测试,增强了mock能力。
整体上,Spring Boot Test支持的测试种类,大致可以分为如下三类:
功能测试过程中的几个关键要素及支撑方式如下:
增加spring-boot-starter-test依赖,使用@RunWith和@SpringBootTest注解,即可开始测试。
添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
一旦依赖了spring-boot-starter-test,下面这些类库将被一同依赖进去:
1. 单元测试
@RunWith(SpringRunner.class) @SpringBootTest public class SpringBootApplicationTests { @Autowired private UserService userService; @Test public void testAddUser() { User user = new User(); user.setName("john"); user.setAddress("earth"); userService.add(user); } }
@RunWith是Junit4提供的注解,将Spring和Junit链接了起来。假如使用Junit5,不再需要使用@ExtendWith注解,@SpringBootTest和其它@*Test默认已经包含了该注解。
@SpringBootTest替代了spring-test中的@ContextConfiguration注解,目的是加载ApplicationContext,启动spring容器。
使用@SpringBootTest时并没有像@ContextConfiguration一样显示指定locations或classes属性,原因在于@SpringBootTest注解会自动检索程序的配置文件,检索顺序是从当前包开始,逐级向上查找被@SpringBootApplication或@SpringBootConfiguration注解的类。
2. 功能测试
一般情况下,使用@SpringBootTest后,Spring将加载所有被管理的bean,基本等同于启动了整个服务,此时便可以开始功能测试。
由于web服务是最常见的服务,且我们对于web服务的测试有一些特殊的期望,所以@SpringBootTest注解中,给出了webEnvironment参数指定了web的environment,该参数的值一共有四个可选值:
注:如果当前服务的classpath中没有包含web相关的依赖,spring将启动一个非web的ApplicationContext,此时的webEnvironment就没有什么意义了。
3. 切片测试
所谓切片测试,官网文档称为 “slice” of your application,实际上是对一些特定组件的称呼。这里的slice并非单独的类(毕竟普通类只需要基于JUnit的单元测试即可),而是介于单元测试和集成测试中间的范围。
slice是指一些在特定环境下才能执行的模块,比如MVC中的Controller、JDBC数据库访问、Redis客户端等,这些模块大多脱离特定环境后不能独立运行,假如spring没有为此提供测试支持,开发者只能启动完整服务对这些模块进行测试,这在一些复杂的系统中非常不方便,所以spring为这些模块提供了测试支持,使开发者有能力单独对这些模块进行测试。
通过@*Test开启具体模块的测试支持,开启后spring仅加载相关的bean,无关内容不会被加载。
使用@WebMvcTest用来校验controllers是否正常工作的示例:
@RunWith(SpringRunner.class) @WebMvcTest(IndexController.class) public class SpringBootTest { @Autowired private MockMvc mvc; @Test public void testExample() throws Exception { //groupManager访问路径 //param传入参数 MvcResult result=mvc.perform(MockMvcRequestBuilders.post("/groupManager").param("pageNum","1").param("pageSize","10")).andReturn(); MockHttpServletResponse response = result.getResponse(); String content = response.getContentAsString(); List<JtInfoDto> jtInfoDtoList = GsonUtils.toObjects(content, new TypeToken<List<JtInfoDto>>() {}.getType()); for(JtInfoDto infoDto : jtInfoDtoList){ System.out.println(infoDto.getJtCode()); } } }
使用@WebMvcTest和MockMvc搭配使用,可以在不启动web容器的情况下,对Controller进行测试(注意:仅仅只是对controller进行简单的测试,如果Controller中依赖用@Autowired注入的service、dao等则不能这样测试)。
Spring为了避免的繁琐难懂的xml配置,引入大量annotation进行系统配置,确实减轻了配置工作量。由此,理解这些annotation变得尤为重要,一定程度上讲,对Spring Boot Test的使用,就是对其相关annotation的使用。
1. 按功能分类
从功能上讲,Spring Boot Test中的注解主要分如下几类:
@TestConfiguration
等。提供一些测试相关的配置入口。@MockBean
等。提供mock支持。@AutoConfigureJdbc
等。以AutoConfigure开头的注解,具有加载测试支持功能的能力。(1) 配置类型的注解
@Component
,在语义上用来指定某个Bean是专门用于测试的。该注解适用于测试代码和正式混合在一起时,不加载被该注解描述的Bean,使用不多。@TestComponent
,它用于补充额外的Bean或覆盖已存在的Bean。在不修改正式代码的前提下,使配置更加灵活。@EnableAutoConfiguration
,与ImportAutoConfiguration
结合使用,以限制所加载的自动配置类。在不修改正式代码的前提下,提供了修改配置自动配置类的能力。@AutoConfigure*
注解中用到的变量名称,例如在@AutoConfigureMockMvc
中定义名为spring.test.mockmvc.webclient.enabled的变量。一般不使用。使用@SpringBootApplication
启动测试或者生产代码,被@TestComponent
描述的Bean会自动被排除掉。如果不是则需要向@SpringBootApplication
添加TypeExcludeFilter。
(2) mock类型的注解
@MockBean
和@SpyBean
这两个注解,在mockito框架中本来已经存在,且功能基本相同。Spring Boot Test又定义一份重复的注解,目的在于使MockBean
和SpyBean
被ApplicationContext管理,从而方便使用。
MockBean和SpyBean功能非常相似,都能模拟方法的各种行为。不同之处在于MockBean是全新的对象,跟正式对象没有关系;而SpyBean与正式对象紧密联系,可以模拟正式对象的部分方法,没有被模拟的方法仍然可以运行正式代码。
(3) 自动配置类型的注解(@AutoConfigure*)
这些注解可以搭配@\*Test
使用,用于开启在@\*Test
中未自动配置的功能。例如@SpringBootTest
和@AutoConfigureMockMvc
组合后,就可以注入org.springframework.test.web.servlet.MockMvc
。
自动配置类型有两种方式:
@SpringBootTest
)时显示添加。@WebMvcTest
注解时,隐式添加了@AutoConfigureCache
、@AutoConfigureWebMvc
、@AutoConfigureMockMvc
。(4) 启动测试类型的注解(@*Test)
所有的@*Test注解都被@BootstrapWith注解,它们可以启动ApplicationContext,是测试的入口,所有的测试类必须声明一个@*Test注解。
除了@SpringBootTest
之外的注解都是用来进行切面测试的,他们会默认导入一些自动配。
一般情况下,推荐使用@SpringBootTest
而非其它切片测试的注解,简单有效。若某次改动仅涉及特定切片,可以考虑使用切片测试。
@SpringBootTest
是这些注解中最常用的一个,其中包含的配置项如下:
webEnvironment
详细说明:
2. 相互之间的搭配组合
package sample.test; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import sample.test.domain.VehicleIdentificationNumber; import sample.test.service.VehicleDetails; import sample.test.service.VehicleDetailsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.test.context.junit4.SpringRunner; import static org.mockito.BDDMockito.given; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @AutoConfigureTestDatabase public class SampleTestApplicationWebIntegrationTests { private static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber( "01234567890123456"); @Autowired private TestRestTemplate restTemplate; @MockBean private VehicleDetailsService vehicleDetailsService; @Before public void setup() { given(this.vehicleDetailsService.getVehicleDetails(VIN)) .willReturn(new VehicleDetails("Honda", "Civic")); } @Test public void test() { this.restTemplate.getForEntity("/{username}/vehicle", String.class, "sframework"); } }
其中@RunWith和@*Test必须存在,@AutoConfigure*可以同时配置任意多个,而配置类型的注解可以在需要时添加。
3. 相似注解的区别于联系
(1) @TestComment vs @Comment
@TestComponent
是另一种@Component
,在语义上用来指定某个Bean是专门用于测试的@TestComponent
会被自动排除(2) @TestConfiguration vs @Configuration
@TestConfiguration
是Spring Boot Boot Test提供的,@Configuration
是Spring Framework提供的。@TestConfiguration
实际上是也是一种@TestComponent
,只是这个@TestComponent
专门用来做配置用。@TestConfiguration
和@Configuration
不同,它不会阻止@SpringBootTest
的查找机制,相当于是对既有配置的补充或覆盖。(3) @SpringBootTest vs @WebMvcTest(或@*Test)
转自:沉迷思考的鱼 http://ypk1226.com/2018/11/20/spring-boot/spring-boot-test-2/