与以前版本的 JUnit 不同,JUnit 5 由来自三个不同子项目的几个不同模块组成。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
是启动 JVM 上测试框架的基础。它还定义了用于开发在平台上运行的测试框架的 API。此外,该平台还提供了一个控制台启动器,用于从命令行启动平台,并提供 JUnit 平台套件引擎,用于使用平台上的一个或多个测试引擎运行自定义测试套件。
是新的编程模型和扩展模型的组合,用于在 JUnit 5 中编写测试和扩展。Jupiter 子项目提供了一个用于在平台上运行基于 Jupiter 的测试。
提供了一个用于在平台上运行基于 JUnit 3 和 JUnit 4 的测试。
至少有以下优点:
从 JUnit 4 切换到 JUnit 5 非常简单,步骤如下:
JUnit 5 使用新的 org.junit.jupiter 包,Junit 4 使用的是 org.junit 包。
@Test 注解不再有参数,每个参数都被移到了一个函数中。
@Before 变成了 @BeforeEach
@After 变成了 @AfterEach
@BeforeClass 变成了 @BeforeAll
@AfterClass 变成了 @AfterAll
@Ignore 变成了 @Disabled
@Category 变成了 @Tag
@Rule 和 @ClassRule 没有了,用 @ExtendWith 和 @RegisterExtension 代替
JUnit 5 断言在 org.junit.jupiter.api.Assertions 中。大多数常见的断言,如 assertEquals() 和 assertNotNull(),和以前有所不同,错误信息放在了最后一个参数,例如:
assertEquals(“my message”,1,2) 变为 assertEquals(1,2,”my message”)
大多数断言现在接受一个构造错误信息的lambda,只有当断言失败时才会被调用。
假设已被移至 org.junit.jupiter.api.Assumptions。
同样的假设也存在,但它们支持 BooleanSupplier 以及 Hamcrest 匹配器(http://hamcrest.org/)来匹配条件。Lambdas(类型为 Executable)可以用来在条件满足时执行代码。
在 JUnit 4中,自定义框架通常意味着使用 @RunWith 注释来指定一个自定义的运行器。使用多个运行器是有问题的,通常需要链式或使用 @Rule。在 JUnit 5 中已经得到了简化和改进。
新建 Spring Initializr 项目 junit,项目下新建 entity、controller 类。项目创建示例说明 JUnit 5 的使用。
项目目录结构:
添加依赖,如果已按截图操作,pom.xml 还需引入 Junit 5 依赖:
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
完整的 pom.xml 文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.4version>
<relativePath/>
parent>
<groupId>com.chaoyuegroupId>
<artifactId>junitartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>junitname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
excludes>
configuration>
plugin>
plugins>
build>
project>
application.yml 文件中添加如下配置:
server:
port: 8080
为减少不必要的代码,引入 lombok 依赖。实体类代码如下:
package com.chaoyue.junit.entity;
import lombok.Data;
@Data
public class User {
// @TableId(type = IdType.AUTO)
private Long id; // id
private String username; // 用户名
private String password; // 密码
}
package com.chaoyue.junit.controller;
import com.chaoyue.junit.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class LoginController {
@GetMapping("getUserInfo")
public String getUserInfo() {
// 获取用户信息
User userInfo = new User();
userInfo.setId(1L);
userInfo.setUsername("admin");
userInfo.setPassword("123456");
return userInfo.toString();
}
}
在LoginController 类上使用快捷键 ctrl + shift + t 打开弹窗:
点击【Create New Test…】创建测试类:
测试类添加注解 @SpringBootTest:
package com.chaoyue.junit.controller;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class LoginControllerTest {
@BeforeEach
void setUp() {
}
@AfterEach
void tearDown() {
}
@Test
void getUserInfo() {
}
}
/**
* assertTrue、assertFalse 判断条件是否为 true 或 false
*/
@Test
@DisplayName("测试断言 assertTrue、assertTrue")
void testTrue() {
assertTrue(1 > 2 );
// assertFalse(1 > 2 );
}
/**
* assertEquals、assertNotEquals 判断两个值是否相等
*/
@Test
@DisplayName("测试断言 assertEquals、assertNotEquals")
void testEquals() {
assertEquals(1, 2 );
// assertNotEquals(1, 2 );
}
/**
* assertNull、assertNotNull 判断条件是否为 null 或 not null
*/
@Test
@DisplayName("测试断言 assertNull、assertNotNull")
void testNotNull() {
assertNotNull(new Object());
// assertNull(new Object());
}
/**
* assertTimeout 判断断言是否超时
*/
@Test
@DisplayName("测试断言 assertTimeout")
void testTimeout() {
String result = assertTimeout(ofSeconds(2),() -> {
Thread.sleep(1000);
return "未超时";
});
System.out.println(result);
}
/**
* assertAll 组合断言,当内部所有断言都正确执行才算通过
*/
@Test
@DisplayName("测试组合断言")
void testTAll() {
assertAll("测试组合断言",
() -> {
assertTrue(1 < 2, "断言1");
},
() -> {
assertNotNull(new Object(), "断言2");
},
() -> {
assertEquals(1,1);
}
);
}
/**
* RepeatedTest 重复测试
*/
@RepeatedTest(3)
@DisplayName("重复测试")
void testRepeat() {
System.out.println("重复测试");
}
/**
* ParameterizedTest 参数化测试
*/
@ParameterizedTest
@ValueSource(strings = {"参数1", "参数2", "参数3"})
@DisplayName("参数化测试")
void testParam(String param) {
assertEquals(param, "参数1");
System.out.println(param);
}
PS:JUnit 5 官网:https://junit.org/junit5/