单元测试之_Junit5
前言
Github:https://github.com/HealerJean
一、junit5
介绍
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
的测试引擎。
2、Pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
二、Junit5
基础方法
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");
}
}
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)数组断言 assertArrayEquals
通过
assertArrayEquals
方法来判断两个对象或原始类型的数组是否相等
@Test
@DisplayName("array assertion")
public void array() {
assertArrayEquals(new int[]{1, 2}, new int[] {1, 2});
}
3)组合断言 assertAll
assertAl
l 方法接受多个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)
);
}
4)异常断言 Assertions.assertThrows()
JUnit5
提供了 **Assertions.assertThrows()
** ,配合函数式编程就可以进行使用。
@Test
@DisplayName("异常断言")
public void exceptionTest() {
Assertions.assertThrows(
ArithmeticException.class, () -> {
int i = 1 % 0;
});
}
5)超时断言 Assertions.assertTimeout()
` Junit5
提供了 **
Assertions.assertTimeout()`** 为测试方法设置了超时时间
@Test
@DisplayName("超时测试(如果测试方法时间超过1s将会异常)")
public void timeoutTest() {
Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
}
6)快速失败
1、当满足某一条件,需要退出测试程序时,可以使用快速失败方法
2、当调用快速失败方法时,程序会退出,同时输出失败提示
@Test
@DisplayName("fail")
public void shouldFail() {
fail("This should fail");
}
3、前置条件
JUnit 5
中的前置条件(又叫假设)类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要。注意:前置条件与断言最大的区别就是前置条件不满足的情况下,跳过该方法继续执行别的方法,而不满足断言的话后面的代码都将不会执行
⬤ 当不满足前置条件时,后续输出代码未执行
⬤ 当不满足前置条件时,程序未报错退出,而是终止执行
@DisplayName("测试前置条件")
@Test
void testAssumptions() {
Assumptions.assumeTrue(false, "结果不足true");
log.info("[Junit5Test#testAssumptions] 结果不足true");
}
4、嵌套测试
JUnit 5
可以通过Java
中的内部类和@Nested
注解实现嵌套测试1、外层测试方法的执行,不会驱动内层方法:当内层方法中有
before
或after
等注解时,调用外层测试方法,并不会驱动其提前或最后执行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");
}
}
5)参数化测试
注解 | 功能 |
---|---|
@ValueSource |
为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型 |
@NullSource |
表示为参数化测试提供一个null的入参 |
@EnumSource |
表示为参数化测试提供一个枚举入参 |
@CsvFileSource |
表示读取指定CSV文件内容作为参数化测试入参 |
@CsvFileSource |
表示读取指定CSV文件内容作为参数化测试入参 |
@MethodSource |
表示读取指定方法的返回值作为参数化测试入参(方法的返回值为流) |
1)@ValueSource
入参为基础类型
@ParameterizedTest
@DisplayName("参数化测试")
@ValueSource(ints = {1, 2, 3, 4, 5})
void testParamterized(int i) {
System.out.println(i);java
}
2)@MethodSource
入参为方法返回值类型
@ParameterizedTest
@DisplayName("参数化方法测试")
@MethodSource("stringProvider")
void testParamterized2(String s) {
System.out.println(s);
}
static Stream<String> stringProvider() {
return Stream.of("apple", "banana");
}
4、Test
注解内部 (Junit4
)
1)timeout
timeout
属性用于指定测试方法允许运行的最大时间。如果测试方法在这个时间内没有完成,测试将被视为失败。
/**
* junit4 超时
*/
@Test(timeout = 1000) // 1秒超时
public void junit4TestMethodWithTimeout() throws InterruptedException {
// 测试代码,模拟长时间运行的任务
Thread.sleep(500); // 0.5秒,测试会通过
// Thread.sleep(1500); // 1.5秒,测试会失败
}
/**
* junit5 超时
*/
@org.junit.jupiter.api.Test() // 1秒超时
void junit5testMethodWithTimeout() {
Assertions.assertTimeout(Duration.ofSeconds(1), () -> {
// 测试代码,模拟长时间运行的任务
Thread.sleep(500); // 0.5秒,测试会通过
// Thread.sleep(1500); // 1.5秒,测试会失败
});
}
2)expected
expected
属性(尽管不是@Test
注解的直接属性)用于指定测试方法期望抛出的异常类型。如果测试方法没有抛出指定的异常,测试将被视为失败。
/**
* junit4 异常捕获
*/
@Test(expected = IllegalArgumentException.class)
public void junit4Exception(){
// 测试代码,期望抛出IllegalArgumentException
throw new IllegalArgumentException("This is an expected exception");
}
/**
* junit5 异常捕获
*/
@org.junit.jupiter.api.Test()
public void junit5Exception(){
Assertions.assertThrows(IllegalArgumentException.class, () -> {
// 测试代码,期望抛出IllegalArgumentException
throw new IllegalArgumentException("This is an expected exception");
});
}