一文解读spring boot的@SpringBootTest、@RunWith、webEnvironment等测试注解,比如spring boot的单元测试、切片测试、功能测试以及mock测试

文章目录

  • 1. SpringBootTest引言
  • 2. SpringBootTest介绍
  • 3. 快速开始
    • 3.1 添加依赖
    • 3.2 单元测试
    • 3.3. 功能测试
    • 3.4 切片测试
  • 4. 注解详解
    • 4.1 功能注解
      • 4.1.1 配置类型的注解
      • 4.1.2 mock类型的注解
      • 4.1.3 自动配置类型的注解(@AutoConfigure*)
      • 4.1.4 启动测试类型的注解(@*Test)
    • 4.2.相互之间的搭配组合
    • 4.3 相似注解的区别于联系
      • 4.3.1 @TestComment vs @Comment
      • 4.3.2 @TestConfiguration vs @Configuration
      • 4.3.3 @SpringBootTest vs @WebMvcTest(或@*Test)
  • 5. 参考文档

1. SpringBootTest引言

我们为什么使用@SpringBootTest注解?比如我想测试spring boot是否成功加载jwt的配置信息JwtProperties实例化的对象中,我可以使用@SpringBootTest注解,如下代码所示:

package com.superjson.superjsonmanager;

import com.superjson.superjsonmanager.config.jwt.JwtProperties;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

// 指定需要加载的配置文件,比如application-local.yml
@ActiveProfiles("local")
// 修改启动环境
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SuperJsonManagerApplicationTests {

  @Test
  void contextLoads() {}

  @Autowired
  private JwtProperties jwtProperties;
  @Test
  public void testJwtProperties(){
    System.out.println(jwtProperties);
  }
}

打印输出结果,如下:

一文解读spring boot的@SpringBootTest、@RunWith、webEnvironment等测试注解,比如spring boot的单元测试、切片测试、功能测试以及mock测试_第1张图片

说明已成功加载配置信息。如果不使用@SpringBootTest,可能无法测试与spring boot相关的框架。

如下便详细介绍@SpringBootTest注解。

2. SpringBootTest介绍

Spring TestJUnit等其他测试框架结合起来,提供了便捷高效的测试手段。而Spring Boot Test是在Spring Test之上的再次封装,增加了切片测试,增强了mock能力。

整体上,Spring Boot Test支持的测试种类,大致可以分为如下三类:

  1. 单元测试:一般面向方法,编写一般业务代码时,测试成本较大。涉及到的注解有@Test

  2. 切片测试:一般面向难于测试的边界功能,介于单元测试和功能测试之间。涉及到的注解有@RunWith@WebMvcTest等。

  3. 功能测试:一般面向某个完整的业务功能,同时也可以使用切面测试中的mock能力,推荐使用。涉及到的注解有@RunWith@SpringBootTest等。如上引言所示。

功能测试过程中的几个关键要素及支撑方式如下:

  1. 测试运行环境:通过@RunWith@SpringBootTest启动spring容器。

  2. mock能力:Mockito提供了强大mock功能。

  3. 断言能力:AssertJHamcrestJsonPath提供了强大的断言能力。

3. 快速开始

增加spring-boot-starter-test依赖,使用@RunWith@SpringBootTest注解,即可开始测试。

3.1 添加依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-testartifactId>
    <scope>testscope>
    <version>2.6.0version>
dependency>

一旦依赖了spring-boot-starter-test,如下类库将被一同依赖进去:

  1. JUnitjava测试事实上的标准,默认依赖版本是4.12(JUnit5JUnit4差别比较大,集成方式有不同)。

  2. Spring Test & Spring Boot TestSpring的测试支持。

  3. AssertJ:提供了流式的断言方式。

  4. Hamcrest:提供了丰富的matcher

  5. Mockitomock框架,可以按类型创建mock对象,可以根据方法参数指定特定的响应,也支持对于mock调用过程的断言。

  6. JSONassert:为JSON提供了断言功能。

  7. JsonPath:为JSON提供了XPATH功能。

3.2 单元测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootApplicationTests {

    @Autowired
    private StudentService studentService;

    @Test
    public void testAddStudent() {
        Student student = new Student();
        student.setName("john");
        student.setAddress("earth");
        studentService.add(student);
    }
}

@RunWithJunit4提供的注解,将SpringJunit连接起来。假如使用Junit5不再需要使用@ExtendWith注解,@SpringBootTest和其它@*Test默认已经包含了该注解。

@SpringBootTest替代了spring-test中的@ContextConfiguration注解,目的是加载ApplicationContext,启动spring容器。

使用@SpringBootTest时并没有像@ContextConfiguration一样显示指定locationsclasses属性,原因在于@SpringBootTest注解会自动检索程序的配置文件,检索顺序是从当前包开始,逐级向上查找被@SpringBootApplication@SpringBootConfiguration注解的类。

3.3. 功能测试

一般情况下,使用@SpringBootTest后,Spring将加载所有被管理的bean,基本等同于启动了整个服务,此时便可以开始功能测试。

由于web服务是最常见的服务,且我们对于web服务的测试有一些特殊的期望,所以@SpringBootTest注解中,给出了webEnvironment参数指定了webenvironment,该参数的值一共有四个可选值:

  1. MOCK:此值为默认值,该类型提供一个mock环境,可以和@AutoConfigureMockMvc@AutoConfigureWebTestClient搭配使用,开启Mock相关的功能。注意此时内嵌的服务(servlet容器)并没有真正启动,也不会监听web服务端口。

  2. RANDOM_PORT:启动一个真实的web服务,监听一个随机端口。

  3. DEFINED_PORT:启动一个真实的web服务,监听一个定义好的端口(从application.properties读取)。

  4. NONE:启动一个非webApplicationContext,既不提供mock环境,也不提供真实的web服务。

注:如果当前服务的classpath中没有包含web相关的依赖,spring将启动一个非webApplicationContext,此时的webEnvironment就没有什么意义了。

3.4 切片测试

所谓切片测试,官网文档称为 slice of your application,实际上是对一些特定组件的称呼。

这里的slice并非单独的类(毕竟普通类只需要基于JUnit的单元测试即可),而是介于单元测试和集成测试中间的范围。

slice是指一些在特定环境下才能执行的模块,比如MVC中的ControllerJDBC数据库访问、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());
        }

    }
}

使用@WebMvcTestMockMvc搭配使用,可以在不启动web容器的情况下,对Controller进行测试(注意:仅仅只是对controller进行简单的测试,如果Controller中依赖用@Autowired注入的servicedao等则不能这样测试)。

4. 注解详解

Spring为了避免的繁琐难懂的xml配置,引入大量annotation进行系统配置,确实减轻了配置工作量。

由此,理解这些annotation变得尤为重要,一定程度上讲,对Spring Boot Test的使用,就是对其相关annotation的使用。

4.1 功能注解

从功能上讲,Spring Boot Test中的注解主要分如下几类:

  1. 配置类型:@TestConfiguration等。提供一些测试相关的配置入口。

  2. mock类型:@MockBean等。提供mock支持。

  3. 启动测试类型:@SpringBootTest。以Test结尾的注解,具有加载applicationContext的能力。

  4. 自动配置类型:@AutoConfigureJdbc等。以AutoConfigure开头的注解,具有加载测试支持功能的能力。

4.1.1 配置类型的注解

  1. @TestComponent:该注解是另一种@Component,在语义上用来指定某个Bean是专门用于测试的。该注解适用于测试代码和正式混合在一起时,不加载被该注解描述的Bean,使用不多。

  2. @TestConfiguration:该注解是另一种@TestComponent,它用于补充额外的Bean或覆盖已存在的Bean。在不修改正式代码的前提下,使配置更加灵活。

  3. @TypeExcludeFilters:用来排除@TestConfiguration@TestComponent。适用于测试代码和正式代码混合的场景,使用不多。

  4. @OverrideAutoConfiguration:可用于覆盖@EnableAutoConfiguration,与ImportAutoConfiguration结合使用,以限制所加载的自动配置类。在不修改正式代码的前提下,提供了修改配置自动配置类的能力。

  5. @PropertyMapping:定义@AutoConfigure*注解中用到的变量名称,例如在@AutoConfigureMockMvc中定义名为spring.test.mockmvc.webclient.enabled的变量。一般不使用。

使用@SpringBootApplication启动测试或者生产代码,被@TestComponent描述的Bean会自动被排除掉。如果不是则需要向@SpringBootApplication添加TypeExcludeFilter

4.1.2 mock类型的注解

  1. @MockBean:用于mock指定的class或被注解的属性。

  2. @MockBeans:使@MockBean支持在同一类型或属性上多次出现。

  3. @SpyBean:用于spy指定的class或被注解的属性。

  4. @SpyBeans:使@SpyBean支持在同一类型或属性上多次出现

@MockBean@SpyBean这两个注解,在mockito框架中本来已经存在,且功能基本相同。Spring Boot Test又定义一份重复的注解,目的在于使MockBeanSpyBeanApplicationContext管理,从而方便使用。

MockBeanSpyBean功能非常相似,都能模拟方法的各种行为。不同之处在于MockBean是全新的对象,跟正式对象没有关系;而SpyBean与正式对象紧密联系,可以模拟正式对象的部分方法,没有被模拟的方法仍然可以运行正式代码。

4.1.3 自动配置类型的注解(@AutoConfigure*)

  1. @AutoConfigureJdbc自动配置JDBC

  2. @AutoConfigureCache自动配置缓存。

  3. @AutoConfigureDataLdap自动配置LDAP

  4. @AutoConfigureJson自动配置JSON

  5. @AutoConfigureJsonTesters自动配置JsonTester

  6. @AutoConfigureDataJpa自动配置JPA

  7. @AutoConfigureTestEntityManager自动配置TestEntityManager

  8. @AutoConfigureRestDocs自动配置Rest Docs

  9. @AutoConfigureMockRestServiceServer自动配置MockRestServiceServer

  10. @AutoConfigureWebClient自动配置WebClient

  11. @AutoConfigureWebFlux自动配置WebFlux

  12. @AutoConfigureWebTestClient自动配置WebTestClient

  13. @AutoConfigureMockMvc自动配置MockMvc

  14. @AutoConfigureWebMvc自动配置WebMvc

  15. @AutoConfigureDataNeo4j 自动配置Neo4j

  16. @AutoConfigureDataRedis自动配置Redis

  17. @AutoConfigureJooq自动配置Jooq

  18. @AutoConfigureTestDatabase自动配置Test Database,可以使用内存数据库。

这些注解可以搭配@\*Test使用,用于开启在@\*Test中未自动配置的功能。例如@SpringBootTest@AutoConfigureMockMvc组合后,就可以注入org.springframework.test.web.servlet.MockMvc

自动配置类型有两种方式:

  1. 功能测试(即使用@SpringBootTest)时显示添加。

  2. 一般在切片测试中被隐式使用,例如@WebMvcTest注解时,隐式添加了@AutoConfigureCache@AutoConfigureWebMvc@AutoConfigureMockMvc

4.1.4 启动测试类型的注解(@*Test)

所有的@*Test注解都被@BootstrapWith注解,它们可以启动ApplicationContext是测试的入口,所有的测试类必须声明一个@*Test注解。

  1. @SpringBootTest自动侦测并加载@SpringBootApplication@SpringBootConfiguration中的配置,默认web环境为MOCK,不监听任务端口。

  2. @DataRedisTest测试对Redis操作,自动扫描被@RedisHash描述的类,并配置Spring Data Redis的库。

  3. @DataJpaTest测试基于JPA的数据库操作,同时提供了TestEntityManager替代JPAEntityManager

  4. @DataJdbcTest测试基于Spring Data JDBC的数据库操作。

  5. @JsonTest测试JSON的序列化和反序列化。

  6. @WebMvcTest测试Spring MVC中的controllers

  7. @WebFluxTest测试Spring WebFlux中的controllers

  8. @RestClientTest测试对REST客户端的操作。

  9. @DataLdapTest测试对LDAP的操作。

  10. @DataMongoTest测试对MongoDB的操作。

  11. @DataNeo4jTest测试对Neo4j的操作。

除了@SpringBootTest之外的注解都是用来进行切面测试的,他们会默认导入一些自动配。

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

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

  1. value指定配置属性。

2.properties指定配置属性,和value意义相同。

  1. classes指定配置类,等同于@ContextConfiguration中的class,若没有显示指定,将查找嵌套的@Configuration类,然后返回到SpringBootConfiguration搜索配置。

  2. webEnvironment指定web环境,可选值有:MOCK、RANDOM_PORT、DEFINED_PORT、NONE

webEnvironment详细说明:

  1. MOCK此值为默认值,该类型提供一个mock环境,此时内嵌的服务(servlet容器)并没有真正启动,也不会监听web端口。

  2. RANDOM_PORT启动一个真实的web服务,监听一个随机端口。

  3. DEFINED_PORT启动一个真实的web服务,监听一个定义好的端口(从配置中读取)。

  4. NONE启动一个非webApplicationContext,既不提供mock环境,也不提供真是的web服务。

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

}
  1. @RunWith(SpringRunner.class)JUnit的注解,作用是关联Spring Boot Test,使运行JUnit时同时启动Spring

  2. @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) 作用是启动SpringApplicationContext,参数webEnvironment指定了运行的web环境。

  3. @AutoConfigureTestDatabase作用是启动一个内存数据库,不使用真实的数据库

其中@RunWith@*Test必须存在,@AutoConfigure*可以同时配置任意多个,而配置类型的注解可以在需要时添加。

4.3 相似注解的区别于联系

4.3.1 @TestComment vs @Comment

  1. @TestComponent是另一种@Component,在语义上用来指定某个Bean是专门用于测试的。

  2. 使用@SpringBootApplication服务时,@TestComponent会被自动排除。

4.3.2 @TestConfiguration vs @Configuration

  1. @TestConfigurationSpring Boot Test提供的,@ConfigurationSpring Framework提供的。

  2. @TestConfiguration实际上是也是一种@TestComponent,只是这个@TestComponent专门用来做配置用。

  3. @TestConfiguration@Configuration不同,它不会阻止@SpringBootTest的查找机制,相当于是对既有配置的补充或覆盖。

4.3.3 @SpringBootTest vs @WebMvcTest(或@*Test)

  1. 都可以启动SpringApplicationContext

  2. @SpringBootTest自动侦测并加载@SpringBootApplication@SpringBootConfiguration中的配置,@WebMvcTest不侦测配置,只是默认加载一些自动配置。

  3. @SpringBootTest测试范围一般比@WebMvcTest大。

5. 参考文档

  1. https://www.cnblogs.com/myitnews/p/12330297.html

你可能感兴趣的:(java,springboot,spring,spring,boot,java,后端,单元测试)