1. JUnit5
1. wiki
Junit5
由来自三个不同子项目组成,JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
。
JUnit Platform
: JVM 上启动测试框架的基础,不仅支持 Junit 自制的测试引擎,其他测试引擎也都可以接入。
JUnit Jupiter
: 提供了新的编程模型,是新特性的核心。内部包含了一个测试引擎,用于在 Junit Platform 上运行。
JUnit Vintage
: 由于 JUint 已经发展多年,为了照顾老的项目,JUnit Vintage 提供了兼容 JUnit4.x,Junit3.x 的测试引擎。
执行流程为
2. 引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <properties> <junit-platform.version>1.5.2</junit-platform.version> <junit.version>1.5.2</junit.version> </properties>
<dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-launcher</artifactId> <version>${junit-platform.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency>
|
3. 常用注解
@Test
: 表示方法是测试方法。但是与 JUnit4 的 @Test
不同,他的职责非常单一不能声明任何属性,拓展的测试将会由 Jupiter 提供额外测试
@DisplayName
: 为测试类或者测试方法设置展示名称
@BeforeAll
: 表示在所有单元测试之前执行
@AfterAll
: 表示在所有单元测试之后执行
@BeforeEach
: 表示在每个单元测试之前执行
@AfterEach
: 表示在每个单元测试之后执行
@Disabled
: 表示测试类或测试方法不执行,类似于JUnit4中的 @Ignore
@Tag
: 表示单元测试类别,类似于 JUnit4 中的 @Categories
@Timeout
: 表示测试方法运行如果超过了指定时间将会返回错误
@ExtendWith
: 为测试类或测试方法提供扩展类引用
@ParameterizedTest
: 表示方法是参数化测试
@RepeatedTest
: 表示方法可重复执行
@Nested
: 内嵌单元测试
@TestFactory
: 动态的创建单元测试
1. 参数化测试 @ParameterizedTest
指定入参,将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。
需要引入的包
1 2 3 4 5 6
| <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-params</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency>
|
@ValueSource
: 为参数化测试指定入参来源,支持八大基础类以及 String 类型,Class 类型
@NullSource
: 表示为参数化测试提供一个 null 的入参
@EnumSource
: 表示为参数化测试提供一个枚举入参
@CsvFileSource
:表示读取指定 CSV 文件内容作为参数化测试入参
@MethodSource
:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @ParameterizedTest @ValueSource(strings = {"one", "two", "three"}) @DisplayName("参数化测试1") public void parameterizedTest1(String string) { System.out.println(string); Assertions.assertTrue(StringUtils.isNotBlank(string)); }
@ParameterizedTest @CsvFileSource(resources = "/test.csv") @DisplayName("参数化测试-csv文件") public void parameterizedTest2(String name, Integer age) { System.out.println("name:" + name + ",age:" + age); Assertions.assertNotNull(name); Assertions.assertNotNull(age); }
@ParameterizedTest @MethodSource("method") @DisplayName("方法来源参数") public void testWithExplicitLocalMethodSource(String name) { System.out.println(name); Assertions.assertNotNull(name); }
static Stream<String> method() { return Stream.of("apple", "banana"); }
|
2. 重复测试 @RepeatedTest
允许某个单元测试执行多次,多次运行单元测试可以更加保证测试的准确性,防止一些随机性。
1 2 3 4 5
| @RepeatedTest(10) @DisplayName("重复测试") public void testRepeated() { Assertions.assertTrue(1 == 1); }
|
3. 内嵌单元测试 @Nested
平时我们写单元测试时一般都是一个类对应一个单元测试类。不过有些互相之间有业务关系的类,他们的单元测试完全是可以写在一起,使用内嵌的方式表示,减少测试类的数量防止类爆炸。@Nested
注解,能够以静态内部成员类的形式对测试用例类进行逻辑分组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public class NestedTestDemo {
@Test @DisplayName("Nested") void isInstantiatedWithNew() { System.out.println("最一层--内嵌单元测试"); }
@Nested @DisplayName("Nested2") class Nested2 {
@BeforeEach void Nested2_init() { System.out.println("Nested2_init"); }
@Test void Nested2_test() { System.out.println("第二层-内嵌单元测试"); }
@Nested @DisplayName("Nested3") class Nested3 {
@BeforeEach void Nested3_init() { System.out.println("Nested3_init"); }
@Test void Nested3_test() { System.out.println("第三层-内嵌单元测试"); } } }
}
|
4. 动态的创建单元测试 @TestFactory
@TestFactory
修饰的方法本身并不是单元测试,其会在运行时生成单元测试,通过返回 DynamicTest 的迭代器或流即可获取。
1 2 3 4 5 6 7 8
| @TestFactory @DisplayName("动态测试") Iterator<DynamicTest> dynamicTests() { return Arrays.asList( dynamicTest("第一个动态测试", () -> assertTrue(true)), dynamicTest("第二个动态测试", () -> assertEquals(4, 2 * 2)) ).iterator(); }
|
4. 断言
org.junit.jupiter.api.Assertions
,支持 lambda 表达式
1. 异常断言
1 2 3 4 5 6 7
| @Test @DisplayName("异常测试") public void exceptionTest() { ArithmeticException exception = Assertions.assertThrows( ArithmeticException.class, () -> System.out.println(1 % 0)); }
|
2. 超时断言
1 2 3 4 5 6
| @Test @DisplayName("超时测试") public void timeoutTest() { Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500)); }
|