单元测试:SpringBoot Test
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库,在 Spring Boot 2.2.0 版本之前,spring-boot-starter-test 包含了 JUnit 4 的依赖,Spring Boot 2.2.0 版本之后替换成了 Junit Jupiter (没有@RunWith注解了)。
SpringBootTest默认集成了以下功能:
- JUnit 5: Java单元测试框架
- Spring Test & Spring Boot Test: Spring Boot的测试工具和支持
- AssertJ: 流式断言
- Hamcrest: Hamcrest断言
- Mockito: Java Mock框架
- JSONassert: JSON断言
- JsonPath: XPath for JSON
# 1. 功能分类
从功能上讲,Spring Boot Test中的注解主要分如下几类:
类别 | 示例 | 格式 | 说明 |
---|---|---|---|
配置类型 | @TestConfiguration 等 | 提供一些测试相关的配置入口 | |
mock类型 | @MockBean 等 | 提供mock支持 | |
启动测试类型 | @SpringBootTest | @*Test | 以Test结尾的注解,具有加载applicationContext的能力 |
自动配置类型 | @AutoConfigureJdbc 等 | @AutoConfigure* | 以AutoConfigure开头的注解,具有加载测试支持功能的能力。 |
# 1.1 配置类型的注解
注解 | 作用 | 实践中的使用 |
---|---|---|
@TestComponent | 该注解另一种@Component ,在语义上用来指定某个Bean是专门用于测试的。 | 该注解适用于测试代码和正式混合在一起时,不加载被该注解描述的Bean,使用不多。 |
@TestConfiguration | 该注解是另一种@TestComponent ,它用于补充额外的Bean或覆盖已存在的Bean | 在不修改正式代码的前提下,使配置更加灵活 |
@TypeExcludeFilters | 用来排除@TestConfiguration 和@TestComponent | 适用于测试代码和正式代码混合的场景,使用不多 |
@OverrideAutoConfiguration | 可用于覆盖@EnableAutoConfiguration ,与ImportAutoConfiguration 结合使用,以限制所加载的自动配置类 | 在不修改正式代码的前提下,提供了修改配置自动配置类的能力 |
@PropertyMapping | 定义@AutoConfigure* 注解中用到的变量名称,例如在@AutoConfigureMockMvc 中定义名为spring.test.mockmvc.webclient.enabled的变量 | 一般不使用 |
使用
@SpringBootApplication
启动测试或者生产代码,被@TestComponent
描述的Bean会自动被排除掉。如果不是则需要向@SpringBootApplication
添加TypeExcludeFilter。
# 1.2 mock类型的注解
注解 | 作用 |
---|---|
@MockBean | 用于mock指定的class或被注解的属性(或者说在测试类中排除一个bean,Spring将使用这个mock而不是真正的类,所以不会调用@PostConstruct方法) |
@MockBeans | 使@MockBean 支持在同一类型或属性上多次出现 |
@SpyBean | 用于spy指定的class或被注解的属性 |
@SpyBeans | 使@SpyBeans 支持在同一类型或属性上多次出现 |
@MockBean
和@SpyBean
这两个注解,在mockito框架中本来已经存在,且功能基本相同。Spring Boot Test又定义一份重复的注解,目的在于使MockBean
和SpyBean
被ApplicationContext管理,从而方便使用。
MockBean和SpyBean功能非常相似,都能模拟方法的各种行为。不同之处在于MockBean是全新的对象,跟正式对象没有关系;而SpyBean与正式对象紧密联系,可以模拟正式对象的部分方法,没有被模拟的方法仍然可以运行正式代码。
# 1.3 自动配置类型的注解(@AutoConfigure*)
注解 | 作用 |
---|---|
@AutoConfigureJdbc | 自动配置 JDBC |
@AutoConfigureCache | 自动配置缓存 |
@AutoConfigureDataLdap | 自动配置 LDAP |
@AutoConfigureJson | 自动配置 JSON |
@AutoConfigureJsonTesters | 自动配置 JsonTester |
@AutoConfigureDataJpa | 自动配置 JPA |
@AutoConfigureTestEntityManager | 自动配置 TestEntityManager |
@AutoConfigureRestDocs | 自动配置 Rest Docs |
@AutoConfigureMockRestServiceServer | 自动配置 MockRestServiceServer |
@AutoConfigureWebClient | 自动配置 WebClient |
@AutoConfigureWebFlux | 自动配置 WebFlux |
@AutoConfigureWebTestClient | 自动配置 WebTestClient |
@AutoConfigureMockMvc | 自动配置 MockMvc |
@AutoConfigureWebMvc | 自动配置 WebMvc |
@AutoConfigureDataNeo4j | 自动配置 Neo4j |
@AutoConfigureDataRedis | 自动配置 Redis |
@AutoConfigureJooq | 自动配置 Jooq |
@AutoConfigureTestDatabase | 自动配置Test Database,可以使用内存数据库 |
这些注解可以搭配@\*Test
使用,用于开启在@\*Test
中未自动配置的功能。例如@SpringBootTest
和@AutoConfigureMockMvc
组合后,就可以注入org.springframework.test.web.servlet.MockMvc
。
“自动配置类型”有两种使用方式:
- 在功能测试(即使用
@SpringBootTest
)时显示添加。- 一般在切片测试中被隐式使用,例如
@WebMvcTest
注解时,隐式添加了@AutoConfigureCache
、@AutoConfigureWebMvc
、@AutoConfigureMockMvc
。
实现原理 与
spring-boot-autoconfigure
中的@\*AutoConfiguration
实现略有不同,Test包中的@AutoConfigure\*
通过DeterminableImports
接口作为指定代码的识别入口,通过ImportAutoConfiguration
注解作为配置入口,从Test包下的spring.factories
(opens new window)读取配置文件,每个@AutoConfigure\*
中都可以包含多个Spring Boot的@\*AutoConfiguration
,例如:AutoConfigureWebMvc
# 1.4 启动测试类型的注解(@*Test)
所有的 @*Test
注解都被 @BootstrapWith
注解,它们可以启动 ApplicationContext,是测试的入口,所有的测试类必须声明一个 @*Test
注解。
注解 | 作用 | |
---|---|---|
@SpringBootTest | 自动侦测并加载@SpringBootApplication或@SpringBootConfiguration中的配置,默认web环境为MOCK,不监听任务端口 | |
@DataRedisTest | 测试对Redis操作,自动扫描被@RedisHash描述的类,并配置Spring Data Redis的库 | |
@DataJpaTest | 测试基于JPA的数据库操作,同时提供了TestEntityManager替代JPA的EntityManager | |
@DataJdbcTest | 测试基于Spring Data JDBC的数据库操作 | |
@JsonTest | 测试JSON的序列化和反序列化 | |
@WebMvcTest | 测试Spring MVC中的controllers | |
@WebFluxTest | 测试Spring WebFlux中的controllers | |
@RestClientTest | 测试对REST客户端的操作 | |
@DataLdapTest | 测试对LDAP的操作 | |
@DataMongoTest | 测试对MongoDB的操作 | |
@DataNeo4jTest | 测试对Neo4j的操作 |
除了
@SpringBootTest
之外的注解都是用来进行切面测试的,他们会默认导入一些自动配置,点击官方docs (opens new window)查看详情。
一般情况下,推荐使用@SpringBootTest
而非其它切片测试的注解,简单有效。若某次改动仅涉及特定切片,可以考虑使用切片测试。
@SpringBootTest
是这些注解中最常用的一个,其中包含的配置项如下:
配置名称 | 说明 |
---|---|
value | 指定配置属性 |
properties | 指定配置属性,和value意义相同 |
classes | 指定配置类,等同于@ContextConfiguration 中的class,若没有显示指定,将查找嵌套的@Configuration 类,然后返回到SpringBootConfiguration 搜索配置 |
webEnvironment | 指定web环境,可选值有:MOCK 、RANDOM_PORT 、DEFINED_PORT 、NONE |
webEnvironment
详细说明:
可选值 | 说明 |
---|---|
MOCK | 此值为默认值,该类型提供一个mock环境,此时内嵌的服务(servlet容器)并没有真正启动,也不会监听web端口。 |
RANDOM_PORT | 启动一个真实的web服务,监听一个随机端口。 |
DEFINED_PORT | 启动一个真实的web服务,监听一个定义好的端口(从配置中读取)。 |
NONE | 启动一个非web的ApplicationContext,既不提供mock环境,也不提供真是的web服务。 |
# 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;
/**
* {@code @SpringBootTest} with a random port for {@link SampleTestApplication}.
*
* @author Phillip Webb
*/
@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");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
- @RunWith(SpringRunner.class)是JUnit的注解,作用是关联Spring Boot Test,在运行JUnit时同时启动Spring
- @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) 作用是启动Spring的ApplicationContext,参数webEnvironment指定了运行的web环境
- @AutoConfigureTestDatabase 作用是启动一个内存数据库,不使用真实的数据库
其中@RunWith和@Test必须存在,@AutoConfigure可以同时配置任意多个,而配置类型的注解可以在需要时添加。
# 3. 相似注解的区别和联系
# 3.1 @TestComment vs @Comment
@TestComponent
是另一种@Component
,在语义上用来指定某个Bean是专门用于测试的- 使用@SpringBootApplication服务时,
@TestComponent
会被自动排除
# 3.2 @TestConfiguration vs @Configuration
@TestConfiguration
是Spring Boot Boot Test提供的,@Configuration
是Spring Framework提供的。@TestConfiguration
实际上是也是一种@TestComponent
,只是这个@TestComponent
专门用来做配置用。@TestConfiguration
和@Configuration
不同,它不会阻止@SpringBootTest
的查找机制,相当于是对既有配置的补充或覆盖。
# 3.3 @SpringBootTest vs @WebMvcTest(或@*Test)
- 都可以启动 Spring 的 ApplicationContext
@SpringBootTest
自动侦测并加载@SpringBootApplication
或@SpringBootConfiguration
中的配置,@WebMvcTest
不侦测配置,只是默认加载一些自动配置。@SpringBootTest
测试范围一般比@WebMvcTest
大。
# 4. 小结
本文主要介绍了Spring Boot Test中新增的注解,这些注解分为这几个类型:配置类型、mock类型、启动测试类型、自动配置类型。
- “配置类型”中的
@TestComponent
、@TestConfiguration
、@OverrideAutoConfiguration
使配置更加灵活。 - 封装了
mockito
的@MockBean
和@SpyBean
,使其可以自然的注入到Spring容器中。 - 每个测试类必须包含一个“启动测试类型”的注解(
@\*Test
),同时可以根据需要添加”自动配置类型”的注解(@AutoConfigure*
)。 @SpringBootTest
是最常用的“启动测试类型”注解