Spring为了避免的繁琐难懂的xml配置,引入大量annotation进行系统配置,确实减轻了配置工作量。由此,理解这些annotation变得尤为重要,一定程度上讲,对Spring Boot Test的使用,就是对其相关annotation的使用。

掌握这些annotation(及部分关联的类),可以从注解功能分类,相互之间的搭配组合,及相似注解的差异这三方面着手。

1.按功能分类

本文仅讨论Spring Boot Test(版本:2.1.1.BUILD-SNAPSHOT)中的注解,原Spring Test中的注解将在其他文章中讨论。

由于使用这些注解的使用方式大多比较简单,为避免干扰阅读,本文不再罗列代码示例。若有想观看示例的开发者,可以查看GitHub官方Samplespring-boot-test和spring-boot-test-autoconfigure的单元测试

从功能上讲,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或被注解的属性
@MockBeans 使@MockBean支持在同一类型或属性上多次出现
@SpyBean 用于spy指定的class或被注解的属性
@SpyBeans 使@SpyBeans支持在同一类型或属性上多次出现

@MockBean@SpyBean这两个注解,在mockito框架中本来已经存在,且功能基本相同。Spring Boot Test又定义一份重复的注解,目的在于使MockBeanSpyBean被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

“自动配置类型”有两种使用方式:

  1. 在功能测试(即使用@SpringBootTest)时显示添加。
  2. 一般在切片测试中被隐式使用,例如@WebMvcTest注解时,隐式添加了@AutoConfigureCache@AutoConfigureWebMvc@AutoConfigureMockMvc

实现原理
spring-boot-autoconfigure中的@\*AutoConfiguration实现略有不同,Test包中的@AutoConfigure\*通过DeterminableImports接口作为指定代码的识别入口,通过ImportAutoConfiguration注解作为配置入口,从Test包下的spring.factories读取配置文件,每个@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查看详情。

一般情况下,推荐使用@SpringBootTest而非其它切片测试的注解,简单有效。若某次改动仅涉及特定切片,可以考虑使用切片测试。

@SpringBootTest是这些注解中最常用的一个,其中包含的配置项如下:

配置名称 说明
value 指定配置属性
properties 指定配置属性,和value意义相同
classes 指定配置类,等同于@ContextConfiguration中的class,若没有显示指定,将查找嵌套的@Configuration类,然后返回到SpringBootConfiguration搜索配置
webEnvironment 指定web环境,可选值有:MOCKRANDOM_PORTDEFINED_PORTNONE

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

}
  • @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大。

3.4 @MockBean vs @SpyBean

详见1.2 mock类型的注解

4. 小结

本文主要介绍了Spring Boot Test中新增的注解,笔者将这些注解分为这几个类型:配置类型、mock类型、启动测试类型、自动配置类型。

  1. “配置类型”中的@TestComponent@TestConfiguration@OverrideAutoConfiguration使配置更加灵活。
  2. 封装了mockito@MockBean@SpyBean,使其可以自然的注入到Spring容器中。
  3. 每个测试类必须包含一个“启动测试类型”的注解(@\*Test),同时可以根据需要添加”自动配置类型”的注解(@AutoConfigure*)。
  4. @SpringBootTest是最常用的“启动测试类型”注解

参考:
Spring Boot Reference Guide
Spring、Spring Boot和TestNG测试指南 - @TestConfiguration - 颇忒脱 - SegmentFault 思否
OverrideAutoConfiguration (Spring Boot Docs 2.1.0.RELEASE API)
Spring Boot 1.4: @MockBean and @SpyBean | GoorooThink Tech News | Articles | Skills Analytics | Gooroo


文章作者: 沉迷思考的鱼
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 沉迷思考的鱼 !
评论
 上一篇
Spring Boot 入门介绍 Spring Boot 入门介绍
一个完善的应用程序,常常需要这些特性:精简明确的配置,快速集成第三方组件,统一的打包部署方式,方便单元测试/功能测试,良好的监控能力等。Spring Boot出现之前,这些都需要开发者自行摸索解决,得到的方案可能大同小异,在尝到“约定大于配
2018-11-27
下一篇 
Spring Boot Test (一、快速入门) Spring Boot Test (一、快速入门)
提起“单元测试”这几个字,一般开发者会条件反射般想起:“工作忙,没时间”,这是一个客观上的事实,在急于求成的大环境下,规范的单元测试却需要一些明确的代码产出及覆盖率指标,这的确很让人头疼。早几年的关于单元测试的文章,不停的鼓吹其好处,却对时
2018-11-17
  目录