JUnit5入门学习_Junit

 

前言

相比 junit4 这个相对落后的技术,我写的博文比较简短,所以 junit5 我打算稍微深入一下,所以大家会发现我的 junit5 的篇幅是长于 junit4 的

junit5 的结构

platform 提供平台功能,jupiter 是核心,vintage 用来兼容 junit3 和 junit4

junit5 = junit platform + junit jupiter + junit vintage

实际上需要引入 junit-platform-launcher junit-jupiter-engine junit-vintage-engine 这样三个依赖,但是实际上一个 junit-jupiter 依赖包就足够了,因为其中包含了 junit-jupiter-engine 然后 junit-jupiter-engine 依赖包中又含有 junit-platform-launcher,所以足够了,vintage 是为了兼容低版本的 junit 所以不重要

Junit5 引入依赖

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>RELEASE</version>
    <scope>test</scope>
</dependency>

注意

junit5 在 idea 2017.1 版本运行会报错的,这一点得通过升级 idea 来解决!

https://stackoverflow.com/questions/47831893/intellij-does-not-run-junit5-tests

注解

测试方法的注解执行顺序从上到下

并且我们可以发现在 @BeforeAll 注解的方法执行时候不需要执行类的构造器,而 @BeforeEach 必须会实例化一下类,如果执行 @Test 时候存在一个实例化的类就去用他,没有就自己先去执行类的构造器,换句话说就是每次执行到 @BeforeEach 前会调一次构造器,我们看下图执行结果就明白了:

JUnit5入门学习_Junit_02

  • @BeforeAll 所有测试开始前执行,且需要是 static 方法
  • @BeforeEach 每个测试方法开始前执行
  • @Test 测试的方法
  • @AfterEach
  • @AfterAll

测试方法相关的注解

  • @Nested 写一个嵌套类,里头可以写测试类,因为是被嵌套的,优先级低于普通的测试方法
  • @Disabled 忽略的测试
  • @DisplayName 用来展示测试名字,不加这个著名名字则默认使用方法名作为测试名字
  • @ParameterizedTest
  • @RepeatedTest 重复执行测试方法多次

运行器的注解

  • @RunWith(xxx.class)
    • @SelectPackages
    • @IncludePackages
    • @SelectClasses
    • @Tag
    • @IncludeTags
    • @ExcludeTags
参数化与数据驱动

ValueSource

话不多说直接看实例 1

下面 @ParameterizedTest 表示参数化测试方法,@NullSource 表示无资源,@EmptySource 表示空资源,@ValueSource 表示有资源,其中含有两个,实际执行这个方法会被执行 4 遍转入不同的值

简单多参建议使用 ValueSource

@ParameterizedTest
@NullSource
@EmptySource
@ValueSource(stirngs = {"1", "2"})
public void demo(String str) {
    assert str.equals("1");
}

MethodSource

话不多说再来看实例 2

通过 @ParameterizedTest 标注参数化的测试方法,通过 MethodSource 表名测试数据来源一个测试方法,数据来源方法注意名字一致,然数据来源方法返回数据。

若 @MethodSource 后不加东西,它会默认去找和参数化测试方法同名(重载)的方法

涉及到完整的对象的参数建议使用 MethodSource,推荐使用它来做数据驱动,数据源可以是 yaml,json,csv,xml 等其他,最多的还是 yaml 和 json

@ParameterizedTest
@MethodSource("function1")
public void demo(String str) {
    system.out.println(str);
}

public static Stream<String> function1() {
    return Stream.of("param1", "param2");
    /*
    // 这种写法可以在 arguments 中传多种不同的参数
    return Stream.of(arguments("param1"), arguments("param2"));
    */
}

CsvSource

话不多说来看实例 3

至于 @CsvFileSource 资源来自于外部文件数据(resources)

简单的数据驱动建议使用 CsvSource

@ParameterizedTest
@CsvSource({
    "num1,	1",
    "num2,	2",
    "num3,	3"
})
public void demo(String str, int n) {
    // ...
}
断言

支持多个条件断言,传统测试框架一旦第一个断言出错下面的就不再执行了,junit5 支持断言多个,但需要 jdk8 lambda 表达式的支持

Assertions.assertAll("demo", 
	() -> assertEquals(1, 2);
	() -> assertEquals(2, 2);
	() -> assertEquals(2, 3);
);
测试套件

这个测试套件的概念在 junit4 也是有的,在 testng 中可以使用 testng.xml 来做测试套件管理,在 junit5 中可以使用代码的形式来做,即可运行指定包的测试类

@RunWith(JUnitPlatform.class)
@SuiteDisplayName("This is a test suite")
@SelectPackages("包名")
public class TestSuite {
}
并行问题

使用 mvn 并行

安装一些 maven 插件,比如 surefile,这个插件可以做到测试类并行,方法并行,甚至可以做到 testng 中 xml 的并行,详细操作 demo 可以查看 maven 的 surefile 插件官网介绍,mvn 的这个特点在我们持续集成的时候还是蛮有实用性的

mvn -Dtest=Xxx test
mvn -Dtest=Xxx,Y*y test
mvn -Dtest=Xxx#myTest test
mvn -Dsurefile.rerunFailingTestsCount=2 test
动态测试

junit5 提供了动态测试用例编写的可能,需要 @TestFactory 注解

场景:已经拿到结果的一个数据文件,就可以通过 junit5 动态测试来生成测试用例,并且产生一个很好的测试报告。因此我们知道动态测试是依赖于已经知道结果数据,我们要做的就是写动态测试代码去比较,和最终生成一个好看测试报告

@TestFactory
public List<DynamicTest> demo() {
    return Arrays.asList(
        // 第一个动态测试用例
    	DynamicTest.dynamicTest("First Test", () -> {
            // 逻辑...
            Assertions.assertEquals(1, 1);
        });
        
        // 第二个动态测试用例
        DynamicTest.dynamicTest("Second Test", () -> {
            // 逻辑...
            Assertions.assertEquals(1, 2);
        });
    );
}