之前把我的mall项目晋级到Spring Boot 2.7的时分,许多之前的测验办法都不能用了,原来是Spring Boot Test现已晋级支撑JUnit 5了。今日咱们来聊聊新版Spring Boot Test的运用,有了它,咱们就不需求再运用main办法来测验了!

SpringBoot实战电商项目mall(50k+star)地址:github.com/macrozheng/…

JUnit 简介

JUnit是一款Java语言的单元测验结构,现在大多数Java开发环境都现已支撑它了。JUnit测验也就是所谓的白盒测验,在程序员知道程序内部逻辑的基础上进行的测验,运用JUnit能让咱们快速地完结单元测验。Spring Boot Test将JUnit和其他测验结构结合起来,供给了快捷高效的测验手法,现在Spring Boot 2.7版本选用的是JUnit 5。

常用注解

在运用Spring Boot Test之前,咱们先来了解下它常用的注解,这对运用它很有协助,详细参考下表即可!

注解 作用
@SpringBootTest 用于指定测验类启用Spring Boot Test,默认会供给Mock环境
@ExtendWith 假如只想启用Spring环境进行简略测验,不想启用Spring Boot环境,能够装备扩展为:SpringExtension
@Test 指定办法为测验办法
@TestMethodOrder 用于装备测验类中办法的履行次序策略,装备为OrderAnnotation时,按@Order次序履行
@Order 用于装备办法的履行次序,数字越低履行次序越高
@DisplayName 用于指定测验类和测验办法的别名
@BeforeAll 在测验类的一切测验办法前履行一次,可用于大局初始化
@AfterAll 在测验类的一切测验办法后履行一次,可用于大局毁掉资源
@BeforeEach 在测验类的每个测验办法前都履行一次
@AfterEach 在测验类的每个测验办法后都履行一次
@Disabled 禁用测验办法
@RepeatedTest 指定测验办法重复履行
@ParameterizedTest 指定参数化测验办法,相似重复履行,从@ValueSource中获取参数
@ValueSource 用于参数化测验指定参数
@AutoConfigureMockMvc 启用MockMvc的自动装备,可用于测验接口

根本运用

下面咱们来聊聊这些注解的根本运用,经过它们能够完成一些根本的单元测验。

集成Spring Boot Test

假如你想在项目中集成Spring Boot Test的话,需求先在pom.xml中添加如下依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

最简略的测验

  • 咱们先来一个最简略的单元测验,运用@SpringBootTest注解启用单元测验,运用@Test指定测验办法,运用Assertions类的办法来断语成果是否符合预期,详细代码如下。
/**
 * JUnit根本测验
 * Created by macro on 2022/10/11.
 */
@SpringBootTest
public class FirstTest {
    @Test
    public void test() {
        int a=1;
        Assertions.assertEquals(1,a);
    }
}
  • 然后点击测验办法左边按钮即可进行测验。

别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!

  • 履行完结后咱们在IDEA的履行窗口中就能够看到办法测验经过了,因为运用@SpringBootTest启用了Spring Boot环境,日志中会输出Spring Boot的banner。

别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!

指定测验办法次序

  • 咱们能够经过@TestMethodOrder注解和@Order注解来指定一切测验办法的履行次序,详细代码如下。
/**
 * JUnit指定办法测验次序
 * Created by macro on 2022/10/10.
 */
@ExtendWith(SpringExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MethodOrderTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(MethodOrderTest.class);
    @Test
    @Order(1)
    @DisplayName("order为1的办法")
    void lowOrder(){
        LOGGER.info("lowOrder method");
    }
    @Test
    @Order(10)
    @DisplayName("order为10的办法")
    void highOrder(){
        LOGGER.info("highOrder method");
    }
}
  • 点击类左边测验按钮,能够直接运转该类中的一切测验办法。

别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!

  • 这儿因为咱们运用了@DisplayName注解给测验办法取了个别名,而且咱们运用了@ExtendWith指定了运转环境为Spring而不是Spring Boot,所以日志中不会出现Spring Boot的banner,履行速度也更快。

别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!

生命周期测验

  • 咱们还能够经过JUnit 5的生命周期注解来履行测验办法,比如在@BeforeAll注解指定的办法中做大局初始化,在@AfterAll注解指定的办法中做资源的毁掉,详细代码如下。
/**
 * JUnit生命周期测验
 * Created by macro on 2022/10/10.
 */
@ExtendWith(SpringExtension.class)
public class LifecycleTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleTest.class);
    @BeforeAll
    static void allInit(){
        LOGGER.info("allInit():在一切办法前履行,只履行一次");
    }
    @BeforeEach
    void eachInit(){
        LOGGER.info("eachInit():在测验办法前履行,每个测验办法前都履行");
    }
    @Test
    void successTest() {
        LOGGER.info("successTest():办法履行成功");
    }
    @AfterEach
    void eachDown(){
        LOGGER.info("eachDown():在测验办法后履行,每个测验办法后都履行");
    }
    @AfterAll
    static void allDown(){
        LOGGER.info("allDown():在测验办法后履行,每个测验办法后都履行");
    }
}
  • 测验完结后,控制台输出日志如下。

别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!

断语的运用

咱们能够经过Assertions类中供给的断语API来断语测验成果。

  • 例如咱们能够运用fail办法直接断语办法履行失利并输出提示信息。
/**
 * JUnit断语测验
 * Created by macro on 2022/10/11.
 */
@ExtendWith(SpringExtension.class)
public class AssertTest {
    @Test
    void failTest() {
        Assertions.fail("failTest():办法履行失利");
    }
}
  • 测验办法履行后会直接抛出异常信息。

别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!

  • 还能够经过assertTrueassertNullassertEquals这类办法来断语成果是否符合预期。
/**
 * JUnit断语测验
 * Created by macro on 2022/10/11.
 */
@ExtendWith(SpringExtension.class)
public class AssertTest {
    @Test
    void failTest() {
        Assertions.fail("failTest():办法履行失利");
    }
    @Test
    void trueTest(){
        Assertions.assertTrue(1==1);
    }
    @Test
    void trueFalse(){
        Assertions.assertFalse(3<=2);
    }
    @Test
    void nullTest(){
        String str = null;
        Assertions.assertNull(str);
    }
    @Test
    void notNullTest(){
        String str = "test";
        Assertions.assertNotNull(str);
    }
    @Test
    void equalsTest(){
        String str1 = "test";
        String str2 = "test";
        Assertions.assertEquals(str1,str2);
    }
    @Test
    void notEqualsTest(){
        String str1 = "test";
        String str2 = "test";
        Assertions.assertNotEquals(str1,str2);
    }
}
  • 也能够运用assertThrows办法来断语办法中抛出的异常。
/**
 * JUnit断语测验
 * Created by macro on 2022/10/11.
 */
@ExtendWith(SpringExtension.class)
public class AssertTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleTest.class);
    @Test
    void throwsTest(){
        Assertions.assertThrows(NullPointerException.class,()->{
            String str = null;
            LOGGER.info(str.toLowerCase());
        });
    }
}
  • 还可经过assertTimeout办法断语办法的履行时间。
/**
 * JUnit断语测验
 * Created by macro on 2022/10/11.
 */
@ExtendWith(SpringExtension.class)
public class AssertTest {
    @Test
    void timeoutTest(){
        Assertions.assertTimeout(Duration.ofMillis(1000),()->{
            long sleepTime = 2000;
            ThreadUtil.sleep(sleepTime);
            LOGGER.info("timeoutTest():休眠{}毫秒",sleepTime);
        });
    }
}
  • 或者经过assertAll办法将几个断语结合起来运用,Assertions类中供给的工具办法许多,详细能够参考它的代码。
/**
 * JUnit断语测验
 * Created by macro on 2022/10/11.
 */
@ExtendWith(SpringExtension.class)
public class AssertTest {
    @Test
    void assertAllTest(){
        Assertions.assertAll(()->{
            trueTest();
        },()->{
            nullTest();
        },()->{
            equalsTest();
        });
    }
}

其他测验

  • Spring Boot Test除了上述测验功用,还能够运用@Disabled来禁用某个测验办法。
/**
 * JUnit其他测验
 * Created by macro on 2022/10/10.
 */
@ExtendWith(SpringExtension.class)
public class OtherTest {
    @Test
    @Disabled("用于测验@Disabled注解")
    void disabledTest() {
        LOGGER.info("disabledTest():办法被履行");
    }
}
  • 也能够运用@RepeatedTest来完成循环测验。
/**
 * JUnit其他测验
 * Created by macro on 2022/10/10.
 */
@ExtendWith(SpringExtension.class)
public class OtherTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleTest.class);
    private static int count = 0;
    @RepeatedTest(3)
    void repeatedTest() {
        count++;
        LOGGER.info("repeatedTest():重复履行第{}次",count);
    }
}
  • 还能够经过@ParameterizedTest来进行参数化测验。
/**
 * JUnit其他测验
 * Created by macro on 2022/10/10.
 */
@ExtendWith(SpringExtension.class)
public class OtherTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleTest.class);
    @ParameterizedTest
    @ValueSource(ints = {1,2,3})
    public void parameterizedTest(int a){
        LOGGER.info("parameterizedTest():a={}",a);
    }
}
  • 运转以上测验办法后,详细测验成果如下。

别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!

项目实战

上面介绍了Spring Boot Test的根本运用,下面咱们结合项目来运用下它。

Dao层测验

假如咱们的项目需求对数据拜访层Dao中的办法进行测验的话,直接注入Mapper接口,在测验办法中直接调用即可,这儿对根据ID查询品牌的Mapper办法进行测验。

/**
 * Dao层办法测验
 * Created by macro on 2022/10/11.
 */
@SpringBootTest
public class MapperTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(MapperTest.class);
    @Autowired
    private PmsBrandMapper brandMapper;
    @Test
    void testGetById(){
        long id = 6;
        PmsBrand pmsBrand = brandMapper.selectByPrimaryKey(id);
        LOGGER.info("brand name:{}",pmsBrand.getName());
        Assertions.assertEquals("小米",pmsBrand.getName());
    }
}

Service层测验

对事务层Service中的办法测验也是一样的,直接注入Service接口,在测验办法中直接调用即可,这儿对根据ID查询品牌的Service办法进行测验。

/**
 * Service层办法测验
 * Created by macro on 2022/10/11.
 */
@SpringBootTest
public class ServiceTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceTest.class);
    @Autowired
    private PmsBrandService brandService;
    @Test
    void testGetById(){
        long id = 6;
        PmsBrand pmsBrand = brandService.getBrand(id);
        LOGGER.info("brand name:{}",pmsBrand.getName());
        Assertions.assertEquals("小米",pmsBrand.getName());
    }
}

Controller层测验

关于Controller层办法进行测验,有时咱们需求模仿恳求,运用MockMvc即可,这儿模仿测验下分页查询品牌列表的接口。

/**
 * Controller层办法测验
 * Created by macro on 2022/10/11.
 */
@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTest {
    @Autowired
    private MockMvc mockMvc;
    @Test
    void mvcTest() throws Exception{
        //模仿发送一个恳求拜访分页查询品牌列表的接口
        mockMvc.perform(MockMvcRequestBuilders.get("/brand/list") //设置恳求地址
                .param("pageNum","1") //设置恳求参数
                .param("pageSize","5"))
                .andExpect(MockMvcResultMatchers.status().isOk()) //断语返回状况码为200
                .andDo(MockMvcResultHandlers.print()) //在控制台打印日志
                .andReturn(); //返回恳求成果
    }
}

因为咱们挑选了在控制台输出日志,控制台将输出如下信息。

别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!

总结

今日带大家体会了一把Spring Boot Test,作为Spring Boot官方测验结构,的确功用很强壮。因为其主要基于JUnit 5,和JUnit 5的用法根本一致。运用它进行单元测验,无需启动整个项目,更快更好用!

参考资料

JUnit 5官方文档:junit.org/junit5/docs…

项目源码地址

github.com/macrozheng/…