JUnit5 教程
JUnit5 教程
在本 Junit 教程中,我们将使用示例介绍 JUnit5 的基础知识及其新功能。在 Java 世界中,JUnit 是用于针对 Java 代码实现单元测试的流行框架之一。JUnit 主要帮助开发人员自己在JVM上测试他们的代码。
JUnit5 架构
JUnit 平台
- 在 JVM 上启动测试框架
- 具有 TestEngine API,用于构建在 JUnit 平台上运行的测试框架
JUnit 木星
- 融合用于编写测试的新编程模型和用于扩展的扩展模型
- 添加新的注释,如
@BeforeEach
、、等。@AfterEach
@AfterAll
@BeforeAll
JUnit 复古
- 提供在此新平台上执行以前的 JUnit 版本 3 和 4 测试的支持
JUnit Maven 依赖项
要在项目中实现基于 JUnit5 的测试用例,请在项目的 pom.xml 文件中添加以下依赖项:
- JUnit 5 库
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version> 1.1.1</version>
<scope>test</scope>
</dependency>
- JUnit5 maven surefire 提供程序用于在 IDE 不支持 JUnit5 的情况下执行单元测试(如果 IDE 支持,则不需要这一点)
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.0.2</version>
</dependency>
</dependencies>
</plugin>
JUnit5 新功能
运行时需要 Java 8 或更高版本。但仍然可以测试使用以前 Java 版本编译的代码。它引入了各种新功能。
JUnit 注释
下面列出了其中提供的一些常用的注解:
注解 | 描述 |
---|---|
@测试 | 表示测试方法 |
@DisplayName | 为测试类或测试方法声明自定义显示名称 |
@BeforeEach | 表示注释的方法应该在每个测试方法之前执行 |
@AfterEach | 表示注释的方法应该在每个测试方法之后执行 |
@BeforeAll | 表示注释的方法应该在所有测试方法之前执行 |
@毕竟 | 表示注释的方法应该在所有测试方法之后执行 |
@Disable | 用于禁用测试类或测试方法 |
@Nested | 表示注释的类是嵌套的非静态测试类 |
@标签 | 声明用于过滤测试的标签 |
@ExtendWith | 注册自定义扩展 |
package com.journaldev;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class JUnit5Sample1Test {
@BeforeAll
static void beforeAll() {
System.out.println("**--- Executed once before all test methods in this class ---**");
}
@BeforeEach
void beforeEach() {
System.out.println("**--- Executed before each test method in this class ---**");
}
@Test
void testMethod1() {
System.out.println("**--- Test method1 executed ---**");
}
@DisplayName("Test method2 with condition")
@Test
void testMethod2() {
System.out.println("**--- Test method2 executed ---**");
}
@Test
@Disabled("implementation pending")
void testMethod3() {
System.out.println("**--- Test method3 executed ---**");
}
@AfterEach
void afterEach() {
System.out.println("**--- Executed after each test method in this class ---**");
}
@AfterAll
static void afterAll() {
System.out.println("**--- Executed once after all test methods in this class ---**");
}
}
我们可以在Eclipse -> Run As -> JUnit Test中运行上述 JUnit 测试类。
JUnit 断言
必须使用断言评估每个测试方法是否符合条件,以便测试可以继续执行。JUnit Jupiter 断言保存在 org.junit.jupiter.api.Assertions 类中。所有方法都是静态的。
断言 | 描述 |
---|---|
assertEquals(预期,实际) | 当预期与实际不符时失败 |
assertFalse(表达式) | 当表达式不为假时失败 |
assertNull(实际) | 当实际不为空时失败 |
assertNotNull(实际) | 当实际值为空时失败 |
断言所有() | 对多个断言进行分组,即使其中一个或多个断言失败,每个断言都会被执行 |
断言真(表达式) | 如果表达式不成立则失败 |
断言抛出() | 待测试的类预计会抛出异常 |
@Test
void testAssertEqual() {
assertEquals("ABC", "ABC");
assertEquals(20, 20, "optional assertion message");
assertEquals(2 + 2, 4);
}
@Test
void testAssertFalse() {
assertFalse("FirstName".length() == 10);
assertFalse(10 > 20, "assertion message");
}
@Test
void testAssertNull() {
String str1 = null;
String str2 = "abc";
assertNull(str1);
assertNotNull(str2);
}
@Test
void testAssertAll() {
String str1 = "abc";
String str2 = "pqr";
String str3 = "xyz";
assertAll("numbers",
() -> assertEquals(str1,"abc"),
() -> assertEquals(str2,"pqr"),
() -> assertEquals(str3,"xyz")
);
//uncomment below code and understand each assert execution
/*assertAll("numbers",
() -> assertEquals(str1,"abc"),
() -> assertEquals(str2,"pqr1"),
() -> assertEquals(str3,"xyz1")
);*/
}
@Test
void testAssertTrue() {
assertTrue("FirstName".startsWith("F"));
assertTrue(10 {
throw new IllegalArgumentException("Illegal Argument Exception occured");
});
assertEquals("Illegal Argument Exception occured", exception.getMessage());
}
JUnit5 导入
它的测试类需要org.junit.jupiter.api.Test
import 语句,而不需要org.junit.Test
。此外,测试方法不需要是公共和本地包。
import org.junit.jupiter.api.Test;
JUnit5 假设
假设是org.junit.jupiter.api.Assumptions
类中的静态方法。仅当满足指定条件时,它们才会执行测试,否则测试将被中止。中止的测试不会导致构建失败。当假设失败时,org.opentest4j.TestAbortedException
将抛出并跳过测试。
假设 | 描述 |
---|---|
假设真实 | 当正则条件成立时执行 lamda 函数体,否则跳过测试 |
假设错误 | 当否定条件成立时执行 lamda 函数体,否则将跳过测试 |
假设 | 如果假设成立,则测试方法的一部分将执行,并且 lambda 之后的所有内容都将执行,无论 assumingThat() 中的假设是否成立 |
@Test
void testAssumeTrue() {
boolean b = 'A' == 'A';
assumeTrue(b);
assertEquals("Hello", "Hello");
}
@Test
@DisplayName("test executes only on Saturday")
public void testAssumeTrueSaturday() {
LocalDateTime dt = LocalDateTime.now();
assumeTrue(dt.getDayOfWeek().getValue() == 6);
System.out.println("further code will execute only if above assumption holds true");
}
@Test
void testAssumeFalse() {
boolean b = 'A' != 'A';
assumeFalse(b);
assertEquals("Hello", "Hello");
}
@Test
void testAssumeFalseEnvProp() {
System.setProperty("env", "prod");
assumeFalse("dev".equals(System.getProperty("env")));
System.out.println("further code will execute only if above assumption hold");
}
@Test
void testAssumingThat() {
System.setProperty("env", "test");
assumingThat("test".equals(System.getProperty("env")),
() -> {
assertEquals(10, 10);
System.out.println("perform below assertions only on the test env");
});
assertEquals(20, 20);
System.out.println("perform below assertions on all env");
}
JUnit 嵌套测试类
嵌套测试允许创建嵌套类并执行其所有测试方法。内部类必须是非静态的。只需使用@Nested注释内部类,其中的所有测试方法都将被执行。
@BeforeAll
static void beforeAll() {
System.out.println("**--- JUnit5Sample4Test :: beforeAll :: Executed once before all test methods ---**");
}
@BeforeEach
void beforeEach() {
System.out.println("**--- JUnit5Sample4Test :: beforeEach :: Executed before each test method ---**");
}
@AfterEach
void afterEach() {
System.out.println("**--- JUnit5Sample4Test :: afterEach :: Executed after each test method ---**");
}
@AfterAll
static void afterAll() {
System.out.println("**--- JUnit5Sample4Test :: afterAll :: Executed after all test method ---**");
}
@Nested
class InnerClass {
@BeforeEach
void beforeEach() {
System.out.println("**--- InnerClass :: beforeEach :: Executed before each test method ---**");
}
@AfterEach
void afterEach() {
System.out.println("**--- InnerClass :: afterEach :: Executed after each test method ---**");
}
@Test
void testMethod1() {
System.out.println("**--- InnerClass :: testMethod1 :: Executed test method1 ---**");
}
@Nested
class InnerMostClass {
@BeforeEach
void beforeEach() {
System.out.println("**--- InnerMostClass :: beforeEach :: Executed before each test method ---**");
}
@AfterEach
void afterEach() {
System.out.println("**--- InnerMostClass :: afterEach :: Executed after each test method ---**");
}
@Test
void testMethod2() {
System.out.println("**--- InnerMostClass :: testMethod2 :: Executed test method2 ---**");
}
}
}
JUnit 测试异常
在某些情况下,方法预计会在特定条件下抛出异常。如果给定的方法没有抛出指定的异常,assertThrows 将测试失败。
Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("Illegal Argument Exception occured");
});
assertEquals("Illegal Argument Exception occured", exception.getMessage());
JUnit 测试执行
单元测试可以通过多种方式执行,其中两种方式如下:
- 使用 Eclipse IDE Oxygen.3a (4.7.3a) 发布并打开要执行的测试文件。右键单击文件并选择选项 Runs As,然后选择 JUnit Test
- 在 Windows 命令提示符下使用 mvn test 命令
概括
我们通过一些示例探索了 JUnit5 及其新功能。我们还研究了如何使用 JUnit 注释、断言、假设、异常以及编写嵌套测试类。
您可以从我们的GitHub 存储库下载完整的示例项目。