JUnit 5 单元测试教程
点赞再看,动力无限。 微信搜「程序猿阿朗 」。
本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章。
在软件开发过程中,我们通常都需要测试自己的代码运行是否正常,可能对一个函数进行简单测试,也可能是多个功能的组合测试。不管使用哪种方式,都是为了更好的测试我们的代码是否存在逻辑缺陷。测试对于软件开发是非常必要的。
JUnit 5 介绍
在 Java 中比较有名的测试工具是 JUnit ,通常我们使用 JUnit 可以对一个逻辑单元进行测试,因此也叫单元测试。多个单元测试组合测试,可以确保我们的程序符合预期。JUnit 单元测试可以在开发阶段发现问题,让我们可以提前修复代码,因此十分重要。
JUnit 5 和 JUnit
JUnit 是一个 Java 语言的开源测试框架,使用 JUnit 让我们使用注解就可以进行单元测试,很是方便。
JUnit 5 是 JUnit 的升级版本,JUnit 5 使用了 Java 8 及更高版本的 Java 语言特性,如函数编程,流式编码等,因此更加强大。JUnit 5 进行单元测试的可读性更强,编写更加容易,且可以轻松扩展。
JUnit 5 基本组件
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform
JUnit Platform 是 JUnit 的基础框架,使用 JUnit Platform 才能在 JVM 启动测试,JUnit Platform 还定义了 TestEngine
测试引擎,是JUnit 测试的基础。
JUnit Jupiter
JUnit Jupiter 提供了单元测试常见的注解以及扩展接口,想要方便的进行 JUnit 单元测试,那么 Jupiter 模块就必不可少。
JUnit Vintage
JUnit Vintage 提供了对 JUnit 3 和 JUnit 4 的测试支持。
JUnit 5 依赖
使用注解进行 JUnit 单元测试,直接引入 junit-jupiter
即可。
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
JUnit 5 常用注解
@Test
为一个 public void
方法添加 @Test
注释,允许我们对这个方法进行测试。
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* @author:https://www.wdbyte.com
**/
class JUnitTestIsDog {
@Test
public void testIsDog() {
String name = "cat";
Assertions.assertEquals(name, "dog");
}
}
上面的代码中使用了 Assertions.assertEquals(name, "dog")
来判断是否 name
变量是否是 dog
,Assertions
是 JUnit
提供的断言工具,后面会详细介绍。
在 idea
中运行可以到的错误日志,提示预期是 dog
,实际是 cat
org.opentest4j.AssertionFailedError:
Expected :cat
Actual :dog
<Click to see difference>
如果是符合预期的,那么运行会显示正确标志。
@Test
public void testIsDog2() {
String name = "dog";
Assertions.assertEquals(name, "dog");
}
testIsDog2
方法测试通过。
@BeforeAll
使用 @BeforeAll
可以在单元测试前初始化部分信息,@BeforeAll
只能使用在静态方法上,被注解的方法会在测试开始前运行一次。
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
* @author:https://www.wdbyte.com
**/
class JUnitBeforeAll {
@BeforeAll
public static void init() {
System.out.println("初始化,准备测试信息");
}
@Test
public void testIsDog() {
String name = "dog";
Assertions.assertEquals(name, "dog");
System.out.println("is dog");
}
@Test
public void testIsCat() {
String name = "cat";
Assertions.assertEquals(name, "cat");
System.out.println("is cat");
}
}
这会输出:
初始化,准备测试信息
is cat
is dog
@BeforeEach
使用 @BeforeEach
注解的方法,会在每一个 @Test
注解的方法运行前运行一次。
class JUnitBeforeAll {
@BeforeAll
public static void init() {
System.out.println("初始化,准备测试信息");
}
@BeforeEach
public void start(){
System.out.println("开始测试...");
}
@Test
public void testIsDog() {
String name = "dog";
Assertions.assertEquals(name, "dog");
System.out.println("is dog");
}
@Test
public void testIsCat() {
String name = "cat";
Assertions.assertEquals(name, "cat");
System.out.println("is cat");
}
}
这会输出:
初始化,准备测试信息
开始测试...
is cat
开始测试...
is dog
@AfterAll
@AfterAll
注解只能使用在静态方法上,被注解的方法会在所有单元测试运行完毕后运行一次。
class JUnitBeforeAll {
@BeforeAll
public static void init() {
System.out.println("初始化,准备测试信息");
}
@BeforeEach
public void start(){
System.out.println("开始测试...");
}
@Test
public void testIsDog() {
//...
}
@Test
public void testIsCat() {
//...
}
@AfterAll
public static void close() {
System.out.println("结束,准备退出测试");
}
}
这会输出:
初始化,准备测试信息
开始测试...
is cat
开始测试...
is dog
结束,准备退出测试
@AfterEach
使用 @AfterEach
注解的方法,会在每一个 @Test
注解的方法运行结束前运行一次。
class JUnitBeforeAll {
@BeforeAll
public static void init() {
System.out.println("初始化,准备测试信息");
}
@BeforeEach
public void start(){
System.out.println("开始测试...");
}
@Test
public void testIsDog() { //... }
@Test
public void testIsCat() { //... }
@AfterEach
public void end(){
System.out.println("测试完毕...");
}
@AfterAll
public static void close() {
System.out.println("结束,准备退出测试");
}
}
这会输出:
初始化,准备测试信息
开始测试...
is cat
测试完毕...
开始测试...
is dog
测试完毕...
结束,准备退出测试
@Disabled
被 @Disabled
注解的方法不在参与测试,下面对 testIsDog
方法添加了 @Disabled
注解。
class JUnitBeforeAll {
@BeforeAll
public static void init() {
System.out.println("初始化,准备测试信息");
}
@BeforeEach
public void start(){
System.out.println("开始测试...");
}
@Disabled("由于xx原因,关闭 testIsDog 测试")
@Test
public void testIsDog() {
String name = "dog";
Assertions.assertEquals(name, "dog");
System.out.println("is dog");
}
@Test
public void testIsCat() {
String name = "cat";
Assertions.assertEquals(name, "cat");
System.out.println("is cat");
}
@AfterEach
public void end(){
System.out.println("测试完毕...");
}
@AfterAll
public static void close() {
System.out.println("结束,准备退出测试");
}
}
这会输出:
初始化,准备测试信息
开始测试...
is cat
测试完毕...
由于xx原因,关闭 testIsDog 测试
结束,准备退出测试
@DisplayName
使用 @DisplayName
注解可以自定义测试方法的显示名称,下面为两个测试方法自定义名称。
class JUnitBeforeAll {
@BeforeAll
public static void init() {
System.out.println("初始化,准备测试信息");
}
@BeforeEach
public void start() {
System.out.println("开始测试...");
}
@DisplayName("是否是狗")
@Disabled
@Test
public void testIsDog() {
String name = "dog";
Assertions.assertEquals(name, "dog");
System.out.println("is dog");
}
@DisplayName("是否是猫")
@Test
public void testIsCat() {
String name = "cat";
Assertions.assertEquals(name, "cat");
System.out.println("is cat");
}
@AfterEach
public void end() {
System.out.println("测试完毕...");
}
@AfterAll
public static void close() {
System.out.println("结束,准备退出测试");
}
}
在 idea
中运行后,可以看到配置的中文名称。
@ParameterizedTest
使用注解 @ParameterizedTest
结合 @ValueSource
,可以对不用的入参进行测试。下面的示例使用 @ParameterizedTest
来开始参数化单元测试,name
属性用来定义测试名称, @ValueSource
则定义了两个测试值。
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class JUnitParam {
//@Test
@DisplayName("是否是狗")
@ValueSource(strings = {"dog", "cat"})
@ParameterizedTest(name = "开始测试入参 {0} ")
public void testIsDog(String name) {
Assertions.assertEquals(name, "dog");
}
}
这会输出:
@Order
在类上增加注解 @TestMethodOrder
,然后在方法上使用 @Order
指定顺序,数字越小优先级越搞,可以保证测试方法运行顺序。
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.condition.EnabledOnJre;
import static org.junit.jupiter.api.condition.JRE.JAVA_19;
@TestMethodOrder(OrderAnnotation.class)
public class JUnitOrder{
@Test
@DisplayName("测试是否是狗")
@Order(2)
public void testIsDog() {
String name = "dog";
Assertions.assertEquals(name, "dog");
System.out.println("is dog");
}
@DisplayName("是否是猫")
@Test
@Order(1)
public void testIsCat() {
String name = "cat";
Assertions.assertEquals(name, "cat");
System.out.println("is cat");
}
}
这会输出:
is cat
is dog
其他注解
@EnabledOnJre(JAVA_19)
只在 JRE 19 环境运行,否则运行会输出:Disabled on JRE version: xxx
.
@RepeatedTest(10)
重复测试,参数 10 可以让单元测试重复运行 10 次。
JUnit 5 常用断言
在上面的例子中,已经用到了 assertEquals
来判断结果是否符合预期,assertEquals
是类 org.junit.jupiter.api.Assertions
中的一个方法;除此之外,还几乎包括了所有我们日常测试想要用到的判断方法。
下面是一些演示:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class JunitAssert {
@DisplayName("是否是狗")
@Test
public void testIsDog() {
String name = "dog";
Assertions.assertNotNull(name);
Assertions.assertEquals(name, "dog");
Assertions.assertNotEquals(name, "cat");
Assertions.assertTrue("dog".equals(name));
Assertions.assertFalse("cat".equals(name));
}
@DisplayName("是否是猫")
@Test
public void testIsCat() {
String name = "cat";
Assertions.assertNull(name, "name is not null");
}
}
在 testIsDog
中演示了一些常用的判断方法,且都可以通过验证。在 testIsCat
方法中进行了 null
值判断,显然这里无法通过测试,会抛出自定义异常 name is not null
。
这会输出:
org.opentest4j.AssertionFailedError: name is not null ==>
Expected :null
Actual :cat
<Click to see difference>
预期是一个 null
值,实际上是一个 cat
字符串。
Maven JUnit 测试
在 Maven 中进行 JUnit 测试,可以通过命令 mvn test
开始测试,默认情况下会测试所有依赖了当前源码的 JUnit 测试用例。
准备被测 Preson类放在 src.main.java.com.wdbyte.test.junit5
.
package com.wdbyte.test.junit5;
public class Person {
public int getLuckyNumber() {
return 7;
}
}
编写测试类 PersonTest 放在 src.test.java.com.wdbyte.test.junit5
. 这里判断获取到的幸运数字是否是 8 ,明显方法返回的是 7 ,所以这里是测试会报错。
package com.wdbyte.test.junit5;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("测试 Presion")
class PersonTest {
@DisplayName("测试幸运数字")
@Test
void getLuckyNumber() {
Person person = new Person();
Assertions.assertEquals(8, person.getLuckyNumber());
}
}
在 pom.xml 中引入 maven junit 测试依赖插件。
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
执行测试命令:mvn test
➜ junit5-jupiter-starter git:(master) ✗ mvn test
[INFO] Scanning for projects...
[INFO] ....
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.wdbyte.test.junit5.PersonTest
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.031 s <<< FAILURE! - in com.wdbyte.test.junit5.PersonTest
[ERROR] getLuckyNumber Time elapsed: 0.026 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: <8> but was: <7>
at com.wdbyte.test.junit5.PersonTest.getLuckyNumber(PersonTest.java:18)
[INFO]
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR] PersonTest.getLuckyNumber:18 expected: <8> but was: <7>
[INFO]
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.777 s
[INFO] Finished at: 2022-11-17T23:01:09+08:00
[INFO] ------------------------------------------------------------------------
也可以指定类进行测试:mvn -Dtest=PersonTest test
一如既往,文章中代码存放在 Github.com/niumoo/javaNotes.
<完>
文章持续更新,可以微信搜一搜「 程序猿阿朗 」或访问「程序猿阿朗博客 」第一时间阅读。本文 Github.com/niumoo/JavaNotes 已经收录,有很多知识点和系列文章,欢迎Star。
JUnit 5 单元测试教程的更多相关文章
- 使用 JUnit 进行单元测试 - 教程
tanyuanji@126.com 版本历史 JUnit 该教程主要讲解 JUnit 4.x 版本的使用,以及如何在Eclipse IDE 中如何使用JUnit 目录 tanyuanji@126. ...
- JUnit单元测试教程(翻译自Java Code Geeks)
JUnit单元测试教程--终极指南 JUnit单元测试教程终极指南 说明 单元测试简介 1 什么是单元测试 2 测试覆盖 3 Java中的单元测试 JUnit简介 1 使用Eclipse实现简单JUn ...
- JUnit三分钟教程 ---- 实际应用
JUnit三分钟教程 ---- 实际应用 摘自http://lavasoft.blog.51cto.com/62575/65775 接上文"JUnit三分钟教程 ---- 快速起步&qu ...
- JUnit三分钟教程 ---- 快速起步
JUnit三分钟教程 ---- 快速起步 摘自http://lavasoft.blog.51cto.com/62575/65625/ JUnit是个好东西,做大点的项目离不开这东西,实际中用的时候也因 ...
- java如何使用JUnit进行单元测试
注:所有内容都是在eclipse上实现,关于eclipse的安装和jdk的安装配置,请看:http://www.cnblogs.com/fench/p/5914827.html 单元测试是什么? 百度 ...
- JUnit 4 单元测试
Individual Project ——JUnit 4 单元测试 学习到JUnit单元测试,我拿来测试之前写过的一个计算器(两个依存类:Calc.java CalcFunction.java).代码 ...
- Android之如何使用JUnit进行单元测试
转的:http://www.blogjava.net/qileilove/archive/2014/05/19/413824.html Android中如何使用JUnit进行单元测试 在我们日常开发a ...
- 使用Spring配合Junit进行单元测试的总结
最近公司的项目和自己的项目中都用到了spring集成junit进行单元测试,总结一下几种基本的用法: 1.直接对spring中注入的bean进行测试(以DAO为例): 在测试类上添加@RunWith注 ...
- Spring(3)—— Junit框架单元测试
Junit主要用于单元测试,即白盒测试.它是一个开源的由JAVA开发的一个用于测试的框架. Junit的几个基本概念:TestCase,TestSuite,TestFixtrue TestCase:代 ...
- JUnit + Mockito 单元测试(二)
摘自: http://blog.csdn.net/zhangxin09/article/details/42422643 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 入门 ...
随机推荐
- .NET 7 SDK 开始 支持构建容器化应用程序
微软于 8 月 25 日在.NET官方博客上,.NET 7 SDK 将包括对创建容器化应用程序的支持,作为构建发布过程的一部分,从而绕过需要.显式 Docker 构建阶段. 这一决定背后的基本认知是简 ...
- 类似微信聊天小程序-网易云信,IM DEMO小程序版本
类似微信聊天小程序-网易云信,IM DEMO小程序版本 代码地址: https://github.com/netease-im/NIM_Web_Weapp_Demo 云信IM DEMO 小程序版本 ( ...
- 五、frp内网穿透客户端frpc.ini各配置参数详解
[必须]标识头[common]是不可或缺的部分 [必须]frps服务端IPserver_addr = 0.0.0.00.0.0.0为FRP服务端IP,客户端要填写为服务端已配置的对应的IP,或者是服务 ...
- service服务使用CoreDNS提供的域名地址访问
普通的 Service:会生成 servicename.namespace.svc.cluster.local 的域名,会解析到 Service 对应的 ClusterIP 上,在 Pod 之间的调用 ...
- ProxySQL(5):线程、线程池、连接池
文章转载自:https://www.cnblogs.com/f-ck-need-u/p/9281909.html ProxySQL的线程 ProxySQL由多个模块组成,是一个多线程的daemon类程 ...
- MySQL 数据更新过程
文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247486441&idx=1&sn=fcf93709 ...
- 使用Docker Compose部署SpringCloud项目docker-compose.yml文件示例
注意各组件之间的依赖关系 microservice-discovery-eureka: image: reg.itmuch.com/microservice-discovery-eureka port ...
- 7.prometheus监控多个MySQL实例
mysqld_exporter集中部署 集中部署,就是说我们将所有的mysqld_exporter部署在同一台服务器上,在这台服务器上对mysqld_exporter进行统一的管理,下面介绍一下集中部 ...
- 自定义View6 -塔防小游戏:第三篇防御塔随意放置+多组野怪
第一篇:一个防御塔+多个野怪(简易版)第二篇:防御塔随意放置第三篇:防御塔随意放置+多组野怪 1.动态addView防御塔 2.防御塔放置后不可以移动 3.弯曲道路 4.素材替换 第四篇:多波野怪 第 ...
- 洛谷P1438 无聊的数列 (线段树+差分)
变了个花样,在l~r区间加上一个等差数列,等差数列的显著特点就是公差d,我们容易想到用线段树维护差分数组,在l位置加上k,在l+1~r位置加上d,最后在r+1位置减去k+(l-r)*d,这样就是在差分 ...