单元测试-Junit5
# 560.单元测试-Junit5
接下来讲讲 Junit
# 简介
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库。
JUnit5 与之前版本的 Junit 框架有很大的不同,由三个不同子项目的几个不同模块组成:
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
说明:
- JUnit Platform: Junit Platform 是在 JVM 上启动测试框架的基础,不仅支持 Junit 自制的测试引擎,其他测试引擎也都可以接入。简单来说,就是 Junit 不仅仅想当一个测试框架,而是一个测试平台,这个 Platform 则是基础。
- JUnit Jupiter: JUnit Jupiter 提供了 JUnit5 的新的编程模型,是 JUnit5 新特性的核心,内部包含了一个测试引擎,在 Junit Platform 上运行。
- JUnit Vintage: 由于 JUint 已经发展多年,为了照顾老的项目,JUnit Vintage 提供了兼容 JUnit4.x,Junit3.x 的测试引擎。
我们在创建 SpringBoot 的时候,已经引入了 Junit:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
2
3
4
5
分析依赖可知,确实用的是 Junit5:
在代码中,引入的也是 jupiter
:
需要注意的是,在 SpringBoot 2.4 版本之后,移除了 Vintage,想要兼容得自行添加依赖,参考 发行说明 (opens new window):
# JUnit 5’s Vintage Engine Removed from
spring-boot-starter-test
If you upgrade to Spring Boot 2.4 and see test compilation errors for JUnit classes such as
org.junit.Test
, this may be because JUnit 5’s vintage engine has been removed fromspring-boot-starter-test
. The vintage engine allows tests written with JUnit 4 to be run by JUnit 5. If you do not want to migrate your tests to JUnit 5 and wish to continue using JUnit 4, add a dependency on the Vintage Engine, as shown in the following example for Maven:<dependency> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> </exclusion> </exclusions> </dependency>
1
2
3
4
5
6
7
8
9
10
11
SpringBoot 整合 Junit 后,怎么用:
- 编写测试方法,并加上@Test 注解(注意需要使用 Junit5 版本的注解)
- Junit 类 具有 Spring 的功能,可以使用@Autowired。使用@Transactional 标注测的试方法,在测试完成后还会自动回滚
# 常用注解
JUnit5 的注解与 JUnit4 的注解有所变化,更多的可以参考 官网文档 (opens new window),大致如下
- @Test:表示方法是测试方法。但是与 JUnit4 的@Test 不同,他的职责非常单一,不能声明任何属性,拓展的测试将会由 Jupiter 提供额外测试
- @DisplayName:为测试类或者测试方法设置展示名称
- @BeforeEach:表示在每个单元测试之前执行
- @AfterEach:表示在每个单元测试之后执行
- @BeforeAll:表示在所有单元测试之前执行
- @AfterAll:表示在所有单元测试之后执行
- @Tag:表示单元测试类别,类似于 JUnit4 中的@Categories,这里不展开
- @Disabled:表示测试类或测试方法不执行,类似于 JUnit4 中的@Ignore
- @Timeout:表示测试方法运行如果超过了指定时间将会返回错误
- @ExtendWith:为测试类或测试方法提供扩展类引用
- @RepeatedTest:表示方法可重复执行,并可以指定重复次数
# @DisplayName
我们新增一个测试类:
package com.peterjxl.learnspringbootwebadmin;
import org.junit.jupiter.api.Test;
public class Junit5Test {
@Test
void testDisplayName(){
System.out.println("testDisplayName");
}
}
2
3
4
5
6
7
8
9
10
运行结果:默认左侧展示的是类名和方法名:
如果加上了 @DisplayName
:
package com.peterjxl.learnspringbootwebadmin;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("Junit5功能测试类")
public class Junit5Test {
@Test
@DisplayName("测试DisplayName")
void testDisplayName(){
System.out.println("testDisplayName");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
运行结果:
# @BeforeEach
,@AfterEach
新增方法:
@BeforeEach
void testBeforeEach(){
System.out.println("测试就要开始了.....");
}
@AfterEach
void testAfterEach(){
System.out.println("测试结束了.....");
}
2
3
4
5
6
7
8
9
运行结果:
测试就要开始了.....
testDisplayName
测试结束了.....
2
3
@BeforeEach
是会在 每一个 测试方法之前都执行,注意是每一个。我们可以新增多一个测试方法:
@Test
@DisplayName("测试方法2")
void test2(){
System.out.println("test2");
}
2
3
4
5
然后我们直接运行整个测试类,这样每个测试方法都会执行一遍:
运行结果:
测试就要开始了.....
test2
测试结束了.....
测试就要开始了.....
testDisplayName
测试结束了.....
2
3
4
5
6
7
# @Before
@BeforeAll
static void testBeforeAll(){
System.out.println("所有测试就要开始了.....");
}
@AfterAll
static void testAfterAll(){
System.out.println("所有测试结束了.....");
}
2
3
4
5
6
7
8
9
运行结果:
所有测试就要开始了.....
测试就要开始了.....
test2
测试结束了.....
测试就要开始了.....
testDisplayName
测试结束了.....
所有测试结束了.....
2
3
4
5
6
7
8
9
注意 @BeforeAll
和 @AfterAll
的方法必须加上 static。
# @Tag
# @Disabled
@Disabled
的方法相当于不执行:
@Test
@DisplayName("测试方法2")
@Disabled
void test2(){
System.out.println("test2");
}
2
3
4
5
6
# @Timeout
新增方法:
@Test
@Timeout(value = 500, unit = TimeUnit.MILLISECONDS)
void testTimeout() throws InterruptedException {
Thread.sleep(600);
}
2
3
4
5
这里我们指定数值是 500,单位是毫秒,也就是 500 毫秒后超时(也可以不指定单位,默认是秒)
运行结果:
所有测试就要开始了.....
测试就要开始了.....
测试结束了.....
java.util.concurrent.TimeoutException: testTimeout() timed out after 500 milliseconds
... 58 more
2
3
4
5
6
# @ExtendWith
在使用 Spring 时,我们 Spring 整合 Junit (opens new window) 是要用注解 @RunWith
的,不然就不能使用 @Autowired
;
在 SpringBoot 中,我们直接使用 @SpringbootTest
,即可使用 SpringBoot 的功能,而该注解其实是一个复合注解,使用了 @ExtendWith
,@ExtendWith
就相当于 @RunWith
:
@ExtendWith({SpringExtension.class})
public @interface SpringBootTest
2
如果我们想要使用其他平台,就得修改 @ExtendWith
里的值,这就是该注解的作用
# @RepeatedTest
新增方法:
@RpeatedTest(5)
void test5(){
System.out.println("test5");
}
2
3
4
运行结果:
# 源码
已将本文源码上传到 Gitee (opens new window) 或 GitHub (opens new window) 的分支 demo17,读者可以通过切换分支来查看本文的示例代码