目录
1.基本介绍
2.maven中安装JUnit5
3.使用
4.JUnit5命名规则
5.JUnit5常用注解
6.JUnit5断言
7.JUnit5多个类之间的继承关系
8.JUnit5参数化
(1)使用场景:
(2)使用前需在pom.xml文件中导入依赖
(3)参数化需要使用的注解
(4)@ValueSource单参数化
(5)@CsvSource多参数化
(6)@CsvFileSource多参数文件参数化
(7)@MethodSource方法参数化
(8)@EnumSource枚举参数参数化
(9)特殊的参数化
9.超时处理
10.JUnit设置显示名称
11.使用@Nested体现测试用例间的嵌套关系
12.JUnit5指定用例的执行顺序
(1)方法排序
(2)类排序
(3)使用配置文件指定顺序
13.JUnit5重复测试
14.JUnit5标记测试用例
(1)使用步骤
(2)Tag的命名规范
(3)Tag表达式
(4)自定义注解标签
15.JUnit5设置禁用测试用例
1.基本介绍
(1)JUnit5是一个Java语言的单元测试框架
(2)JUnit5包括JUnit Platform、JUnit Jupiter和JUnit Vintage
2.maven中安装JUnit5
在pom.xml配置文件中添加以下依赖
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
3.使用
在测试用例上添加@Test注解
@Test
void test1(){
System.out.println("test1方法被运行");
}
在命令行执行需注意
(1)在pom.xml添加以下插件(可在include中指定命名规则)
<build>
<plugins>
<!-- Maven Surefire Plugin for running tests during the build -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<includes>
<include>**/*.java</include>
</includes>
<excludes>
<!-- 指定不运行的测试类-->
<exclude></exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
(1)要对对应module路径下面执行mvn test命令
(2)要符合JUnit5命令规则, 默认以Test开头或者以Test结尾
IDEA快速生成测试文件:在对应类名上鼠标右键->Go To->Test
命令行执行常用命令
- 执行所有测试类:mvn test
- 执行单个测试类:mvn test -Dtest=包名.类名
- 执行单个测试方法:mvn test -Dtest=包名.类名#方法名
- 执行同一个包下的多个测试类:mvn test -Dtest=包名.类名1,包名.类名2,.....
- 正则匹配执行多个测试类:mvn test -Dtest="包名.*Test"
4.JUnit5命名规则
(1)单元测试代码文件
- 默认写在工程目录:src/test/java
- 不允许写在业务代码目录下
(2)测试资源文件
- 默认写在资源目录:src/test/resources
(3)默认命名规则:以Test开头或者以Test结尾
注意:idea并没有针对文件名做限制,但是使用mven构建时,则不会收集不满足规则要求的用例
5.JUnit5常用注解
(1)@DisplayName("参数"),该注解可为测试用例起一个别名,别名即为写入的参数
(2)@BeforeEach在方法上加上该注解,会让这个方法在(一个测试类中的)每个测试用例执行前都执行一次(即有几个测试用例就会执行几次,@AfterEach同理)
(3)@AfterEach注解,会让这个方法在每个测试用例执行之后都执行一次
(4)@BeforeAll注解,会让这个方法在所有测试用例执行之前执行一次(即不管有多少个测试用例都只会执行一次,@AfterAll同理)
(5)@AfterAll注解,会让这个方法在所有测试用例执行完成之后执行一次
总结:All和Each的区别
- All在一个测试类中,只执行一次,但是Each是有多少个方法就执行几次
- All注解只能修饰static方法,不能修饰普通方法。Each可以修饰普通方法
- 如果是BeforeAll和BeforeEach同时存在,优先执行BeforeAll
- 如果是AfterAll和AfterEach同时存在,优先执行AfterEach,最后执行AfterAll
6.JUnit5断言
使用Assertions类的断言方法,判断方法的实际执行结果和预期结果是否一致(断言失败,就会停止运行,后面的语句不会执行)
Assertions类的断言方法有
- assertEquals(参数1, 参数2):参数1为预期结果,参数2为实际结果,如果一致无输出,不一致会报错
- assertTrue(参数):参数为一个表达式,或者为布尔类型的值,如果为true则无输出,为false则报错
- assertNotNull(参数):若参数不为null则无输出,参数为null则报错
- assertAll("All", ()->断言1, ()->断言2,......):用于执行多个断言,其中一个断言失败,不影响其他断言的执行
assertAll("All",
()-> assertTrue(3 == 1),
()-> assertEquals(3, 1+1));
- assertTimeout(参数1,()->{语句}):参数1为设置的运行时间,如果参数2运行时间超过参数1设置的就会报错
// 该用例设置的是3秒,后面的语句运行时间为4000毫秒即4秒,所以会报错,即断言失败
assertTimeout(Duration.ofSeconds(3), ()->{
sleep(4000);
});
- assertThrows(异常类型, 语句):如果第二个参数抛出了第一个参数指定的异常,则断言成功,反之断言失败
@Test
void main4() {
//该语句抛出了参数指定的异常,所以断言成功,无输出
assertThrows(ArithmeticException.class,()->{double a = 1/0;});
}
7.JUnit5多个类之间的继承关系
如果B类继承A类,两个类都有Test,BeforeAll,BeforeEach,AfterAll,AfterEach,执行子类B类时,执行顺序如下(不是所有注释都可以被继承,具体参考官网):
A-beforeAll --> B-beforeAll -->
A-beforeEach --> B-beforeEach --> A-testA1 --> B-afterEach --> A-AfterEach -->
(A-beforeEach --> B-beforeEach --> A-testA2--> B-afterEach --> A-AfterEach......这样循环执行完A的测试用例才会开始执行B的测试用例) -- >
A-beforeEach --> B-beforeEach --> B-testB1 --> B-afterEach --> A-AfterEach -->
(A-beforeEach --> B-beforeEach --> B-testB2 --> B-afterEach --> A-AfterEach) -- >
B-afterAll --> A-afterAll
8.JUnit5参数化
(1)使用场景:
测试流程相同,测试数据需要根据业务需求切换
(2)使用前需在pom.xml文件中导入依赖
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
(3)参数化需要使用的注解
- 将@Test换成@ParameterizedTest
- 注意:如果@Test和@ParameterizedTest同时使用则会多执行一次
- 单参数化注解为@ValueSource
- 多参数化注解为@CsvSource
- 多参数文件参数化注解为@CsvFileSource
- 方法作为参数化的数据源,注解为@MethodSource
- 枚举参数参数化注解为为@EnumSource
- null参数的参数化注解为@NullSource
- 参数为空的参数化注解为@EmptySource
- 需要null和空都进行参数化,使用@NullAndEmptySource注解,还有其他参数可以使用@ValueSource继续提供
(4)@ValueSource单参数化
ValueSource支持的参数类型:
参数 | 参数的类型 |
---|---|
shorts | short |
bytes | byte |
ints | int |
longs | long |
floats | float |
doubles | double |
chars | char |
booleans | boolean |
strings | java.lang.String |
classes | java.lang.Class |
单参数使用步骤
1)将@Test注解换为@ParameterizedTest注解
2)传递测试数据
使用单参数注解@ValueSource传递参数化的数据内容
传递参数化过程中,需要通过@ValueSource定义的关键字进行类型声明
3)在测试方法上添加形参,接受参数化的数据
@ParameterizedTest
@ValueSource(strings = {"xiaoming","xiaowang"})
void main5(String name) {
System.out.println(name);
}
注意:方法中的形参每次只接收一个参数,所以传入几个参数,方法就执行多少次。当@ValueSource注解只传入一个参数时,大括号可省略
(5)@CsvSource多参数化
使用步骤
1)将@Test注解换为@ParameterizedTest注解
2)传递测试数据
使用多参数注解@ValueSource传递参数化的数据内容
多个参数间需用默认分隔符“,”隔开
3)在测试方法上添加形参,接受多参数的数据
示例:
@ParameterizedTest
@CsvSource({"wangming,12","xiaoli,11","ssli,13"})
void main6(String name, Integer age) {
System.out.println(name + "的年龄是" + age);
}
运行结果:
注意:使用CsvSource注解传递参数化数据,传递的参数格式是一个集合
也可通过以下方法指定分隔符:
@CsvSource(value = {"wangming|12","xiaoli|11","ssli|13"},delimiterString = "|")
(6)@CsvFileSource多参数文件参数化
使用步骤
1)在项目的test/resource中新增测试数据csv文件
2)将@Test注解换为@ParameterizedTest注解
3)传递文件路径@CsvFileSource(resources = "文件路径")
4)在测试方法上添加形参,接受多参数的数据
示例:
将以下数据添加到data.csv文件
wangming,12
xiaoli,11
ssli,13
代码
@ParameterizedTest
@CsvFileSource(resources = "/data.csv")
void main7(String name, Integer age) {
System.out.println(name + "的年龄是" + age);
}
运行结果:
也可通过以下方法指定分隔符:
@CsvFileSource(resources = "/data2.csv",delimiterString = "|")
(7)@MethodSource方法参数化
说明
- 该注解引用方法作为参数化的数据源信息
- 该注解的参数必须是静态的工厂方法,除非测试类被注释为@TestInstance(Lifecycle.PER_CLASS)
- 静态工厂方法的放回值需要和测试方法的参数对应
- 如果在@MethodSource注解中未指明方法名,会自动调用与测试方法同名的静态方法
测试方法参数对应的工厂方法返回值
@ParameterizedTest方法 | 工厂方法 |
---|---|
void test(int) | static int[ ] factory() |
void test(int) | static intString factory() |
void test(String) | static String[ ] factory() |
void test(String) | static List<String> factory() |
void test(String) | static Stream<String> factory() |
void test(String, String) | static String[ ][ ] factory() |
void test(String, int) | static object[ ][ ] factory() |
void test(String, int) | static Stream<object[ ]> factory() |
void test(String, int) | static Stream<Arguments> factory() |
void test(int[ ]) | static int[ ][ ] factory() |
void test(int[ ]) | static Stream<int[ ]> factory() |
void test(int[ ][ ]) | static Stream<int[ ][ ]> factory() |
void test(object[ ]) | static Stream<Object[ ][ ]> factory() |
使用步骤
1)将@Test注解换为@ParameterizedTest注解
2)通过@MethodSource("method")指定数据源的方法
3)定义一个静态方法,提供参数化数据源
4)添加形参,形参的类型要和静态方法返回值内部的元素一致
单参数示例:
@ParameterizedTest
@MethodSource("stringProvider")
void main8(String name){
System.out.println(name);
}
static Stream<String> stringProvider(){
return Stream.of("张三", "李四");
}
运行结果:
多参数示例:
@ParameterizedTest
@MethodSource
void main8(String name, Integer age){
System.out.println(name + "的年龄为" + age);
}
static Stream<Arguments> main8(){
return Stream.of(
Arguments.arguments("张三", 13),
Arguments.arguments("李四", 17)
);
}
运行结果:
(8)@EnumSource枚举参数参数化
说明
1)使用枚举类作为测试数据
2)必须与@ParameterizedTest结合使用
使用步骤
1)创建一个枚举类
2)枚举类作为参数传入测试方法
示例:
public enum Unit{
Harry("Harry",21),
my("my",22),
tuble("tuble", 24);
private final String name;
private final Integer age;
private Unit(String name, Integer age) {
this.name = name;
this.age = age;
}
}
@ParameterizedTest
@EnumSource
void main9(Unit unit){
System.out.println(unit.name + "年龄为:" + unit.age);
}
运行结果:
可通过names关键字,指定枚举对象的范围
@EnumSource(names = {"Harry","my"})
运行结果:
通过mode关键字,指定规则
EXCLUDE规则代表取反,意思是names里面指定了什么,就不执行什么
@EnumSource(mode = EnumSource.Mode.EXCLUDE,names = {"my"})
运行结果:
MATCH_ALL规则代表正则匹配,names里面填写正则表达式,匹配到什么就执行什么
@EnumSource(mode = EnumSource.Mode.MATCH_ALL,names = {"my*"})
运行结果:
(9)特殊的参数化
@NullSource提供null作为参数
@ParameterizedTest
@NullSource
void main10(String para){
System.out.println(para);
}
运行结果:
@EmptySource提供空值作为参数
@ParameterizedTest
@EmptySource
void main11(String para){
assertTrue(para.isEmpty());
}
@NullAndEmptySource注解,对null和空都进行参数化(还有其他参数可以使用@ValueSource继续提供)
@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = {"小明", "小李"})
void main12(String para){
System.out.println(para);
}
运行结果:
9.超时处理
使用JUnit5自带的超时处理。当测试用例执行时间超过设置的执行时间,那么用例结果为执行失败
用法:使用@Timeout(5)注解配置超时时间,括号里的参数填的就是设置的执行时间,单位为秒
示例:
@Test
@Timeout(7)
void main4() throws InterruptedException {
System.out.println("超时用例测试");
sleep(10000);
}
运行结果:
可以通过以下方式设置参数的单位
@Timeout(value = 42, unit = MILLISECONDS),表示42毫秒
unit值如下:
毫秒:MILLISECONDS
秒:SECONDS
分:MINUTES
小时:HOURS
天:DAYS
10.JUnit5设置显示名称
相当于给用例起别名,可以展示在IDE、报告中。
普通方式:使用注解@DisplayName("别名"),可以用在方法和类上
进阶:DisplayName生成器
- 通过注解@DisplayNameGenerator实现生成器
- 通过配置文件配置
DisplayName生成器配置
生成器配置 | 含义 | 案例 |
---|---|---|
Standard | 默认配置 | h_test()->h_test() |
Simple | 删除没有参数的方法的尾括号 | h_test()->h_test |
ReplaceUnderscores | 用空格替换下划线,也会去除括号 | h_test()->h test |
IndicativeSentence | 使用类名,方法名 | 类名,h_test() |
(1)例如在类上添加如下注解即为设置默认格式
@DisplayNameGeneration(DisplayNameGenerator.Standard.class)
(2)利用属性文件junit-platform.properties全局配置
步骤如下
1)在路径src/test/resource/junit-platform.properties中添加配置文件
2)在配置文件中添加对应的配置属性(以Simple为例)
junit.jupiter.displayname.generator.default=\
org.junit.jupiter.api.DisplayNameGenerator$Simple
优先级:@DisplayName 》@DisplayNameGenerator 》配置文件
11.使用@Nested体现测试用例间的嵌套关系
方法:定义嵌套类,在每个嵌套类上添加@Nested注解
示例:
public class NestedExampleTest {
@Nested
class AuthorityManage{
@Nested
class Manager{
@Test
void addUser(){
System.out.println("添加用户");
}
@Test
void delUser(){
System.out.println("删除用户");
}
}
@Nested
class EmployeeManage{
@Test
void employeeManage(){
System.out.println("员工管理");
}
}
}
@Nested
class UserManage{
@Test
void userManage(){
System.out.println("用户管理");
}
}
}
运行结果:
12.JUnit5指定用例的执行顺序
分为三种方式:方法排序、类排序、Suite
(1)方法排序
1)方法排序的类型
类型 | 说明 |
---|---|
OrderAnnotation | 使用@Order注解指定排序 |
DisplayName | 根据显示名称排序 |
Random | 随机排序 |
MethodName | 根据方法名称排序 |
2)order注解指定排序步骤:
- 在类上添加注解@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
- 在每个测试用例上添加@Order(1)、@Order(2).......
3)DisplayName根据显示名称排序步骤:
- 在类上添加注解@TestMethodOrder(MethodOrderer.DisplayName.class)
- 在每个测试用例上添加@DispalyName("显示名称")指定显示名称
4)随机排序步骤:
- 在类上添加注解@TestMethodOrder(MethodOrderer.Random.class)
5)方法名称排序步骤:
- 在类上添加注解@TestMethodOrder(MethodOrderer.MethodName.class)
(2)类排序
1)类排序的类型
类型 | 说明 |
---|---|
OrderAnnotation | 使用@Order注解指定排序 |
DisplayName | 根据显示名称排序 |
Random | 随机排序 |
ClassName | 根据方法名称排序 |
用在嵌套类中,需要和@Nested配合使用,使用步骤和方法排序一样
不同的地方在于,第一步中,在类上添加的注解为:
@TestClassOrder(ClassOrderer.类型.class)
(3)使用配置文件指定顺序
步骤如下
1)在配置文件src/test/resource/junit-platform.properties(没有就新建,有就直接写)中写入对应的配置信息
2)可以分别指定方法的默认配置和类的默认配置
#方法排序-设置默认排序方式为随机排序
junit.jupiter.testmethod.order.default=org.junit.jupiter.api.MethodOrderer$Random
#类排序-设置默认排序方式为随机排序
junit.jupiter.testclass.order.default=org.junit.jupiter.api.ClassOrderer$Random
13.JUnit5重复测试
使用注解@RepeatedTest(10)可进行同一个用例的重复测试,参数为重复次数(有了这个注解,不需要再添加@Test,如果添加,则会多执行一次)
可通过以下方式指定重复测试的显示名称(name关键字中只支持这三个变量,不可随意修改,改,其他可修改):
@RepeatedTest(value = 10, name = "{displayName} {currentRepetition} of {totalRepetitions}")
各变量含义
displayName:代表显示名称,如果没有设定,那么会使用方法名称
currentRepetition:当前是第几次重复
totalRepetitions:总共需要重复几次
14.JUnit5标记测试用例
通过Tag标签对用例分组
(1)使用步骤
1)设置标签(一条用例可以设置多个标签)
@Tag("dev")
2)根据标签执行
1.结合Maven执行-修改pom文件
<build>
<plugins>
<!-- Maven Surefire Plugin for running tests during the build -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<includes>
<include>**/*.java</include>
</includes>
<excludes>
<!-- 指定不运行的测试类-->
<exclude></exclude>
</excludes>
<!-- 要执行的标签-->
<groups></groups>
<!-- 不要执行的标签-->
<excludedGroups></excludedGroups>
</configuration>
</plugin>
</plugins>
</build>
- groups表示执行包含标签或者标签表达式的用例
- excludedGroups表示不执行包含该标签或者标签表达式的用例
- 使用mvn clean test执行用例
2.结合maven执行-使用命令行构建
#执行test标签的用例
mvn clean test -Dgroups="test"
#执行不含test标签的用例
mvn clean test -DexcludedGroups="test"
注意:如果使用命令行的同时也配置了pom文件,pom的配置优先级更高
(2)Tag的命名规范
- 不准为空
- 标签不得包含空格
- 标签不得包含ISO控制字符
- 标签不得包含以下任何保留字符
- "," "(、)" "&" "|" "!"
(3)Tag表达式
Tag表达式 | 含义 | 示例 |
---|---|---|
&(在pom文件要写成&) | 表示与关系 | test1&test2表示执行既包含test1又包含test2的标签 |
! | 表示非关系 | !test1表示执行没有test1标签的用例 |
| | 表示或关系 | test1|test2表示执行包含test1或包含test2的标签 |
(4)自定义注解标签
可通过自定义标签,将test注解和tag注解结合到一个注解,减少代码冗余
public class Homework02test {
//使用自定义标签,该自定义标签名为Preprod
@PreprodTest
void main4() {
assertThrows(ArithmeticException.class, () -> {
double a = 1 / 0;
});
}
}
//自定义标签
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Tag("Preprod")
@Test
@interface PreprodTest{
}
15.JUnit5设置禁用测试用例
给用例添加禁用标识,被禁用的用例执行后会添加跳过的状态。
可以禁用测试类、也可以禁用测试方法。
使用方式:添加注解@Disabled,该注解可以有参数,也可以没有,参数为禁用说明,会体现在报告里
注意:如果禁用的是测试类,IDEA不支持,maven构建才支持。禁用的是测试方法,IDEA支持