前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

1、junit5 介绍

1.1、JUnit5 构成

JUnit5 由三个不同子项目的几个不同模块组成。

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

1)JUnit Platform: 是在 JVM 上启动测试框架的基础,不仅支持 Junit 自制的测试引擎,其他测试引擎也都可以接入。

2)JUnit Jupiter: 提供了 JUnit5 的新的编程模型,是 JUnit5 新特性的核心。内部包含了一个测试引擎,用于在 Junit Platform 上运行。

3)JUnit Vintage: 由于 JUint 已经发展多年,为了照顾老的项目,其提供了兼容 JUnit4.x , Junit3.x 的测试引擎。

1.2、Pom

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

2、Junit5 基础方法

2.1、@BeforeEach@AfterEach@BeforeAll@AfterAll

注解 功能
@BeforeEach 表示在每个单元测试之前执行
@AfterEach 表示在每个单元测试之后执行
@BeforeAll 表示在所有单元测试之前执行
@AfterAll 表示在所有单元测试之后执行
@Slf4j
@DisplayName("junit5功能测试")
@SpringBootTest
public class Junit5BaseTest {


    @DisplayName("测试displayname注解")
    @Test
    void testDisplayName() {
        System.out.println(1);
    }

    /**
     * 所有测试方法运行前运行
     */
    @BeforeAll
    public static void beforeAll() {
        System.out.println("Run before all test methods run");
    }

    /**
     * 每个测试方法运行前运行
     */
    @BeforeEach
    public void beforeEach() {
        System.out.println("Run before each test method runs");
    }

    /**
     * 每个测试方法运行完毕后运行
     */
    @AfterEach
    public void afterEach() {
        System.out.println("Run after each test method finishes running");
    }

    /**
     * 在所有测试方法运行完毕后运行
     */
    @AfterAll
    public static void afterAll() {
        System.out.println("Run after all test methods have finished running");
    }

}

image-20230323155042117

2.2、断言

2.2.1、简单断言 Assertions.assert……

方法 说明
Assertions.assertEquals 判断两个对象或两个原始类型是否相等
Assertions.assertNotEquals 判断两个对象或两个原始类型是否不相等
Assertions.assertSame 判断两个对象引用是否指向同一个对象
Assertions.assertNotSame 判断两个对象引用是否指向不同的对象
Assertions.assertTrue 判断给定的布尔值是否为 true
Assertions.assertFalse 判断给定的布尔值是否为 false
Assertions.assertNull 判断给定的对象引用是否为 null
Assertions.assertNotNull 判断给定的对象引用是否不为 null
Assertions.assertTrue 判断条件是否满足

2.2.2、数组断言 assertArrayEquals

通过 assertArrayEquals方法来判断两个对象或原始类型的数组是否相等

@Test
@DisplayName("array assertion")
public void array() {
    assertArrayEquals(new int[]{1, 2}, new int[] {1, 2});
}

image-20230323164334451

2.2.3、组合断言 assertAll

assertAll 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言

1、可以通过 lambda 表达式很容易的提供这些断言

2、前边断言失败,后续代码不会执行

3、组合断言,当组合中的所有断言都通过才是true,否则是false

@Test
@DisplayName("assert all")
public void all() {
    assertAll("组合断言失败",
            () -> Assertions.assertEquals(2, 1 + 1),
            () -> Assertions.assertTrue(false)
    );
}

image-20230323164310722

2.2.4、异常断言 Assertions.assertThrows()

JUnit5 提供了 **Assertions.assertThrows() ** ,配合函数式编程就可以进行使用。

@Test
@DisplayName("异常断言")
public void exceptionTest() {
    Assertions.assertThrows(
            ArithmeticException.class, () -> {
                int i = 1 % 0;
            });

}

image-20230323164204120

2.2.5、超时断言 Assertions.assertTimeout()

` Junit5 提供了 **Assertions.assertTimeout()`** 为测试方法设置了超时时间

@Test
@DisplayName("超时测试(如果测试方法时间超过1s将会异常)")
public void timeoutTest() {
    Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
}

image-20230323164154058

2.2.6、快速失败

1、当满足某一条件,需要退出测试程序时,可以使用快速失败方法

2、当调用快速失败方法时,程序会退出,同时输出失败提示

@Test
@DisplayName("fail")
public void shouldFail() {
    fail("This should fail");
}

image-20230323164134747

2.3、前置条件

JUnit 5 中的前置条件(又叫假设)类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要

注意:前置条件与断言最大的区别就是前置条件不满足的情况下,跳过该方法继续执行别的方法,而不满足断言的话后面的代码都将不会执行

⬤ 当不满足前置条件时,后续输出代码未执行

⬤ 当不满足前置条件时,程序未报错退出,而是终止执行

@DisplayName("测试前置条件")
@Test
void testAssumptions() {
    Assumptions.assumeTrue(false, "结果不足true");
    log.info("[Junit5Test#testAssumptions] 结果不足true");
}

image-20230323164123359

2.4、嵌套测试

JUnit 5 可以通过 Java 中的内部类和@Nested 注解实现嵌套测试

1、外层测试方法的执行,不会驱动内层方法:当内层方法中有 beforeafter 等注解时,调用外层测试方法,并不会驱动其提前或最后执行

2、内层方法的执行,可以驱动外层方法:当外层方法定义了某一数据结果时,内层测试方法可以直接调用该结构

  @Test
  @DisplayName("超时测试(如果测试方法时间超过1s将会异常)")
  public void timeoutTest() {
      Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
  }

  @Nested
  @DisplayName("when new")
  class InnerTest {

      @BeforeEach
      void innerBeforeEach() {
          log.info("[InnerTest#innerBeforeEach] innerBeforeEach");
      }


      @Test
      @DisplayName("is empty")
      void isEmpty() {
          timeoutTest();
          assertTrue(true, "参数不为true");
      }

  }

image-20230323170525603

image-20230323170535526

2.6、参数化测试

注解 功能
@ValueSource 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@NullSource 表示为参数化测试提供一个null的入参
@EnumSource 表示为参数化测试提供一个枚举入参
@CsvFileSource 表示读取指定CSV文件内容作为参数化测试入参
@CsvFileSource 表示读取指定CSV文件内容作为参数化测试入参
@MethodSource 表示读取指定方法的返回值作为参数化测试入参(方法的返回值为流)

2.6.1、@ValueSource

入参为基础类型

@ParameterizedTest
  @DisplayName("参数化测试")
  @ValueSource(ints = {1, 2, 3, 4, 5})
  void testParamterized(int i) {
      System.out.println(i);java
  }

image-20230323170914400

2.6.2、@MethodSource 入参为方法返回值类型

@ParameterizedTest
@DisplayName("参数化方法测试")
@MethodSource("stringProvider")
void testParamterized2(String s) {
    System.out.println(s);
}

static Stream<String> stringProvider() {
    return Stream.of("apple", "banana");
}

image-20230323171052007

3、单元测试覆盖率

1)pom.xml

<!-- 生成单元测试数据插件 -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <configuration>
        <skip>false</skip>
        <testFailureIgnore>true</testFailureIgnore>
        <includes>
            <include>*/*Test.java</include>
        </includes>
    </configuration>
</plugin>
<!-- 生成JaCoCo覆盖率数据插件 -->
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.0</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>report</id>
            <phase>test</phase>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>

2)生成报告

做好上述报告后,直接执行 mvn test 就可以生成单测覆盖率报告了。如果没有什么异常的话,程序会生成单测覆盖率报告文件,地址为: target/site/jacoco/index.html

image-20230702183455345

元素  
Element  
Missed Instructions 代码指令 统计图
Missed Instructions Cov 代码指令 覆盖率
Missed Branches 分支 覆盖 统计图
Missed Branches Cov 分支 覆盖率
Missed 圈复杂度 (循环)未覆盖数
Cxty 圈复杂度 (循环) 总数
Missed 行 未覆盖数
Lines 行总数
Missed 方法 未覆盖数
Methods 方法总数
Missed 类 未覆盖数
Classes 类总数

ContactAuthor