Springboot集成JUnit5优雅进行单元测试

为何使用JUnit5

  • JUnit4被普遍使用,可是许多场景下使用起来语法较为繁琐,JUnit5中支持lambda表达式,语法简单且代码不冗余。
  • JUnit5易扩展,包容性强,能够接入其余的测试引擎。
  • 功能更强大提供了新的断言机制、参数化测试、重复性测试等新功能。
  • ps:开发人员为何还要测试,单测写这么规范有必要吗?其实单测是开发人员必备技能,只不过不少开发人员开发任务过重致使调试完就无论了,没有系统化得单元测试,单元测试在系统重构时能发挥巨大的做用,能够在重构后快速测试新的接口是否与重构前有出入。

简介

如图,JUnit5结构以下:java

  • JUnit Platform: 这是Junit提供的平台功能模块,经过它,其它的测试引擎均可以接入Junit实现接口和执行。
  • JUnit JUpiter:这是JUnit5的核心,是一个基于JUnit Platform的引擎实现,它包含许多丰富的新特性来使得自动化测试更加方便和强大。
  • JUnit Vintage:这个模块是兼容JUnit三、JUnit4版本的测试引擎,使得旧版本的自动化测试也能够在JUnit5下正常运行。

依赖引入

咱们以SpringBoot2.3.1为例,引入以下依赖,防止使用旧的junit4相关接口咱们将其依赖排除。spring

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

经常使用注解

  • @BeforeEach:在每一个单元测试方法执行前都执行一遍数据库

  • @BeforeAll:在每一个单元测试方法执行前执行一遍(只执行一次)api

  • @DisplayName("商品入库测试"):用于指定单元测试的名称spring-boot

  • @Disabled:当前单元测试置为无效,即单元测试时跳过该测试单元测试

  • @RepeatedTest(n):重复性测试,即执行n次测试

  • @ParameterizedTest:参数化测试,3d

  • @ValueSource(ints = {1, 2, 3}):参数化测试提供数据调试

断言

JUnit Jupiter提供了强大的断言方法用以验证结果,在使用时须要借助java8的新特性lambda表达式,均是来自org.junit.jupiter.api.Assertions包的static方法。code

assertTrueassertFalse用来判断条件是否为truefalse

@Test
    @DisplayName("测试断言equals")
    void testEquals() {
        assertTrue(3 < 4);
    }

assertNullassertNotNull用来判断条件是否为·null

@Test
    @DisplayName("测试断言NotNull")
    void testNotNull() {
        assertNotNull(new Object());
    }

assertThrows用来判断执行抛出的异常是否符合预期,并可使用异常类型接收返回值进行其余操做

@Test
    @DisplayName("测试断言抛异常")
    void testThrows() {
        ArithmeticException arithExcep = assertThrows(ArithmeticException.class, () -> {
            int m = 5/0;
        });
        assertEquals("/ by zero", arithExcep.getMessage());
    }

assertTimeout用来判断执行过程是否超时

@Test
    @DisplayName("测试断言超时")
    void testTimeOut() {
        String actualResult = assertTimeout(ofSeconds(2), () -> {
            Thread.sleep(1000);
            return "a result";
        });
        System.out.println(actualResult);
    }

assertAll是组合断言,当它内部全部断言正确执行完才算经过

@Test
    @DisplayName("测试组合断言")
    void testAll() {
        assertAll("测试item商品下单",
                () -> {
                    //模拟用户余额扣减
                    assertTrue(1 < 2, "余额不足");
                },
                () -> {
                    //模拟item数据库扣减库存
                    assertTrue(3 < 4);
                },
                () -> {
                    //模拟交易流水落库
                    assertNotNull(new Object());
                }
        );
    }

重复性测试

在许多场景中咱们须要对同一个接口方法进行重复测试,例如对幂等性接口的测试。

JUnit Jupiter经过使用@RepeatedTest(n)指定须要重复的次数

@RepeatedTest(3)
    @DisplayName("重复测试")
    void repeatedTest() {
        System.out.println("调用");
    }

参数化测试

参数化测试能够按照多个参数分别运行屡次单元测试这里有点相似于重复性测试,只不过每次运行传入的参数不用。须要使用到@ParameterizedTest,同时也须要@ValueSource提供一组数据,它支持八种基本类型以及String和自定义对象类型,使用极其方便。

@ParameterizedTest
    @ValueSource(ints = {1, 2, 3})
    @DisplayName("参数化测试")
    void paramTest(int a) {
        assertTrue(a > 0 && a < 4);
    }

内嵌测试

JUnit5提供了嵌套单元测试的功能,能够更好展现测试类之间的业务逻辑关系,咱们一般是一个业务对应一个测试类,有业务关系的类其实能够写在一块儿。这样有利于进行测试。并且内联的写法能够大大减小没必要要的类,精简项目,防止类爆炸等一系列问题。

@SpringBootTest
@AutoConfigureMockMvc
@DisplayName("Junit5单元测试")
public class MockTest {
    //....
    @Nested
    @DisplayName("内嵌订单测试")
    class OrderTestClas {
        @Test
        @DisplayName("取消订单")
        void cancelOrder() {
            int status = -1;
            System.out.println("取消订单成功,订单状态为:"+status);
        }
    }
}
相关文章
相关标签/搜索