JUnit 5 单元测试教程 - 程序猿阿朗
source link: https://www.cnblogs.com/niumoo/p/16902100.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
点赞再看,动力无限。 微信搜「 程序猿阿朗 」。
本文 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。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK