| 注解 | 说明 |
|---|---|
@DisplayName |
自定义显示名称;类和方法上都可使用 |
@DisplayNameGeneration |
定义显示名称规则;类上都使用 |
@Disable |
禁用测试;类和方法上都可使用 |
@Tag |
标记测试;类和方法上都可使用 |
@DisplayName
使用
@DisplayName注解不但可以放在测试方法上也可以放在测试类的上面。是一个类和方法都可以使用的注解。
eg : @DisplayName("This is a displayname annotation test")
对应括号内是string类型的字符串就是对应的显示内容,string类型内可以填写包含空格、特殊字符甚至表情符号😊。
eg : @DisplayName("😊计算器测试用例 ╯°□°)╯")
作用
作用就是自定义显示名称,自己想怎么显示就怎么显示。
一般情况下的作用就是在 IDE 和构建工具中的测试报告中自定义显示的类名和方法名,当然可以和allure报告结合,在allure报告中同样显示对应方法名和类名
总结
总结为以下几点:
- 带注释的测试类或测试方法声明自定义显示名称
- 通常用于 IDE 和构建工具中的测试报告
- 可包含空格、特殊字符甚至表情符号😊
- 结合Allure报告,可以显示对应方法名和类名
package top.testeru.common;import top.testeru.util.BaseTest;import org.junit.jupiter.api.DisplayName;import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.assertEquals;/*** @program: tutorials* @author: testeru.top* @description: 常用注解测试:显示名称* DisplayName:类+方法注解* @Version 1.0* @create: 2022/1/17 5:01 下午*/@DisplayName("😊Calculator Test╯°□°)╯")public class CommonAnnotation1Test extends BaseTest {@DisplayName("加法")@Testvoid addTest1(){logger.info("Begin Add Test");//加法运算int sum = mySUT.sum(5, 8);logger.info("Operation result:{}",sum);// expected:期望值, actual:运算的实际值assertEquals(13,sum);}@DisplayName("2数相减")@Testvoid subtractTest1(){logger.info("Begin Subtract Test");//减法运算int subtract = mySUT.subtract(5, 8);logger.info("Operation result:{}",subtract);// expected:期望值, actual:运算的实际值assertEquals(-3,subtract);}@DisplayName("字符串拼接🐶")@Testvoid csTest1(){logger.info("Begin ConcatStr Test");//字符串拼接String concatStr = mySUT.concatStr("Hello","Junit5");logger.info("Operation result:{}",concatStr);// expected:期望值, actual:运算的实际值assertEquals("Hello Junit5",concatStr);}@DisplayName("100连续减😱")@Testvoid subtractTest2(){logger.info("Begin Continuous Subtract Test");//100连续减int subtract = mySUT.subtract(50,30,10,60);logger.info("Operation result:{}",subtract);// expected:期望值, actual:运算的实际值assertEquals(-50,subtract);}@DisplayName("平均数😐")@Testvoid avTest1(){logger.info("Begin Average Test");//平均值double average = mySUT.average(55,44,86,72,64);logger.info("Operation result:{}",average);// expected:期望值, actual:运算的实际值assertEquals(64.2,average);}}

@DisplayNameGeneration
使用
类上的注解,不能在方法上使用。
类上声明一次,对应的方法内也是用该类上声明的规则进行对应方法名称的显示。
作用
在类上添加该注解,并在注解内指明对应类,比如:DisplayNameGenerator.ReplaceUnderscores类,它会默认用空格替换名称中的任何下划线,无论是类名上的还是方法名上下划线都会被替换掉。
其实就是自己在类上声明@DisplayNameGeneration注解,并在注解内配置 当前类和方法的显示名称生成器规则
总结
- 配置自定义显示名称生成器
DisplayNameGenerator.ReplaceUnderscores类,它用空格替换名称中的任何下划线
package top.testeru.common;import org.junit.jupiter.api.DisplayNameGeneration;import org.junit.jupiter.api.DisplayNameGenerator;import org.junit.jupiter.api.Test;import top.testeru.util.BaseTest;import static org.junit.jupiter.api.Assertions.assertEquals;/*** @program: tutorials* @author: testeru.top* @description: 常用注解测试:显示名称* DisplayNameGeneration* 空格替换名称中的任何下划线 ReplaceUnderscores* @Version 1.0* @create: 2022/1/17 5:01 下午*/@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)public class Common_Annotation2_Test extends BaseTest {@Testvoid add_test_1(){logger.info("Begin Add Test");//加法运算int sum = mySUT.sum(5, 8);logger.info("Operation result:{}",sum);// expected:期望值, actual:运算的实际值assertEquals(13,sum);}@Testvoid subtract_test_1(){logger.info("Begin Subtract Test");//减法运算int subtract = mySUT.subtract(5, 8);logger.info("Operation result:{}",subtract);// expected:期望值, actual:运算的实际值assertEquals(-3,subtract);}@Testvoid cs_test_1(){logger.info("Begin ConcatStr Test");//字符串拼接String concatStr = mySUT.concatStr("Hello","Junit5");logger.info("Operation result:{}",concatStr);// expected:期望值, actual:运算的实际值assertEquals("Hello Junit5",concatStr);}@Testvoid subtract_test_2(){logger.info("Begin Continuous Subtract Test");//100连续减int subtract = mySUT.subtract(50,30,10,60);logger.info("Operation result:{}",subtract);// expected:期望值, actual:运算的实际值assertEquals(-50,subtract);}@Testvoid av_test_1(){logger.info("Begin Average Test");//平均值double average = mySUT.average(55,44,86,72,64);logger.info("Operation result:{}",average);// expected:期望值, actual:运算的实际值assertEquals(64.2,average);}}
自定义显示名规则
步骤
编写静态内部类
继承Standard
重写方法
generateDisplayNameForClass:声明对应的类名 显示的规则generateDisplayNameForMethod: 声明对应的方法名显示的规则
static class ReplaceCamelCase extends DisplayNameGenerator.Standard {@Overridepublic String generateDisplayNameForClass(Class<?> testClass) {return replaceCamelCase(super.generateDisplayNameForClass(testClass))+ "...";}@Overridepublic String generateDisplayNameForNestedClass(Class<?> nestedClass) {return replaceCamelCase(super.generateDisplayNameForNestedClass(nestedClass));}@Overridepublic String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {//+ DisplayNameGenerator.parameterTypesAsString(testMethod) 方法的括号return this.replaceCamelCase(testClass.getSimpleName()+ ";方法名:" + testMethod.getName()+ ".");}String replaceCamelCase(String camelCase) {StringBuilder result = new StringBuilder();result.append(camelCase.charAt(0));for (int i=1; i<camelCase.length(); i++) {if (Character.isUpperCase(camelCase.charAt(i))) {result.append(' ');result.append(Character.toLowerCase(camelCase.charAt(i)));} else {result.append(camelCase.charAt(i));}}return result.toString().replace("test","Test");}}
注意⚠️
方法/类上有@DisplayName,并且有自定义的显示规则优先级排序「优先级自上而下」:{1 > 2}
- 方法/类上的
@DisplayName - 自定义的显示规则
就是如果 方法/类上有
@DisplayName则直接显示,如果没有则按自定义的显示规则进行显示
完整代码
package com.testeru.base;import org.junit.jupiter.api.DisplayName;import org.junit.jupiter.api.DisplayNameGeneration;import org.junit.jupiter.api.DisplayNameGenerator;import org.junit.jupiter.api.Test;import java.lang.reflect.Method;import static org.junit.jupiter.api.Assertions.assertEquals;/*** @program: tutorials* @author: testeru.top* @description: 自定义显示名称* @Version 1.0* @create: 2022/1/17 5:01 下午*/@DisplayNameGeneration(CommonAnnotation3Test.ReplaceCamelCase.class)public class CommonAnnotation3Test extends BaseTest{@DisplayName("加法")@Testvoid addTest1(){logger.info("Begin Add Test");//加法运算int sum = mySUT.sum(5, 8);logger.info("Operation result:{}",sum);// expected:期望值, actual:运算的实际值assertEquals(13,sum);}@Testvoid subtractTest1(){logger.info("Begin Subtract Test");//减法运算int subtract = mySUT.subtract(5, 8);logger.info("Operation result:{}",subtract);// expected:期望值, actual:运算的实际值assertEquals(-3,subtract);}@Testvoid csTest1(){logger.info("Begin ConcatStr Test");//字符串拼接String concatStr = mySUT.concatStr("Hello","Junit5");logger.info("Operation result:{}",concatStr);// expected:期望值, actual:运算的实际值assertEquals("Hello Junit5",concatStr);}@Testvoid subtractTest2(){logger.info("Begin Continuous Subtract Test");//100连续减int subtract = mySUT.subtract(50,30,10,60);logger.info("Operation result:{}",subtract);// expected:期望值, actual:运算的实际值assertEquals(-50,subtract);}@Testvoid avTest1(){logger.info("Begin Average Test");//平均值double average = mySUT.average(55,44,86,72,64);logger.info("Operation result:{}",average);// expected:期望值, actual:运算的实际值assertEquals(64.2,average);}//标准显示名称生成行为 Standard默认配置static class ReplaceCamelCase extends DisplayNameGenerator.Standard {@Overridepublic String generateDisplayNameForClass(Class<?> testClass) {return replaceCamelCase(super.generateDisplayNameForClass(testClass))+ "...";}@Overridepublic String generateDisplayNameForNestedClass(Class<?> nestedClass) {return replaceCamelCase(super.generateDisplayNameForNestedClass(nestedClass));}@Overridepublic String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {//+ DisplayNameGenerator.parameterTypesAsString(testMethod) 方法的括号return this.replaceCamelCase(testClass.getSimpleName()+ ";方法名:" + testMethod.getName()+ ".");}String replaceCamelCase(String camelCase) {StringBuilder result = new StringBuilder();result.append(camelCase.charAt(0));for (int i=1; i<camelCase.length(); i++) {if (Character.isUpperCase(camelCase.charAt(i))) {result.append(' ');result.append(Character.toLowerCase(camelCase.charAt(i)));} else {result.append(camelCase.charAt(i));}}return result.toString().replace("test","Test");}}}

@Disable
使用
@Disable注解不但可以放在测试方法上也可以放在测试类的上面。是一个类和方法都可以使用的注解。
eg : @Disabled("平均值有bug")
对应括号内是string类型的字符串就是对应方法/类被禁用的原因。也可以不写括号及括号内的string,默认就是返回值 包名.类名.方法 is @Disabled
eg :void top.testeru.common.CommonAnnotation4Test.csTest1() is @Disabled
作用
该注解在方法上声明对应的方法则不被执行,但是方法的类还是依然会被实例化。
如果注解在类上声明则该类下所有测试方法都不被执行,对应类也不会实例化。
总结
- 表示带注释的测试类或测试方法当前已禁用,不应执行
- 可以添加()并声明原因
- 在类级别应用时,该类中的所有测试方法会自动禁用
- 在方法级别应用时,@Disable不会阻止测试类被实例化
- 会阻止执行测试方法和方法级别的生命周期回调
- 例如 @BeforeEach 方法、@AfterEach 方法和相应的扩展 API
package top.testeru.common;import org.junit.jupiter.api.*;import top.testeru.util.BaseTest;import java.lang.reflect.Method;import static org.junit.jupiter.api.Assertions.assertEquals;/*** @program: tutorials* @author: testeru.top* @description: 常用注解测试:* 禁用测试方法:@Disable* 括号内有描述显示描述信息* 不带括号,显示默认信息:{返回值 包名.类名.方法名 is @Disabled}* 显示名称* 自定义显示名称* @Version 1.0* @create: 2022/1/17 5:01 下午*/@DisplayNameGeneration(CommonAnnotation4Test.ReplaceCamelCase.class)public class CommonAnnotation4Test extends BaseTest {@DisplayName("加法")@Testvoid addTest1(){logger.info("Begin Add Test");//加法运算int sum = mySUT.sum(5, 8);logger.info("Operation result:{}",sum);// expected:期望值, actual:运算的实际值assertEquals(13,sum);}@Testvoid subtractTest1(){logger.info("Begin Subtract Test");//减法运算int subtract = mySUT.subtract(5, 8);logger.info("Operation result:{}",subtract);// expected:期望值, actual:运算的实际值assertEquals(-3,subtract);}@DisplayName("字符串拼接🐶")@Test@Disabledvoid csTest1(){logger.info("Begin ConcatStr Test");//字符串拼接String concatStr = mySUT.concatStr("Hello","Junit5");logger.info("Operation result:{}",concatStr);// expected:期望值, actual:运算的实际值assertEquals("Hello Junit5",concatStr);}@Testvoid subtractTest2(){logger.info("Begin Continuous Subtract Test");//100连续减int subtract = mySUT.subtract(50,30,10,60);logger.info("Operation result:{}",subtract);// expected:期望值, actual:运算的实际值assertEquals(-50,subtract);}@Test@Disabled("平均值有bug")void avTest1(){logger.info("Begin Average Test");//平均值double average = mySUT.average(55,44,86,72,64);logger.info("Operation result:{}",average);// expected:期望值, actual:运算的实际值assertEquals(64.2,average);}//标准显示名称生成行为 Standard默认配置static class ReplaceCamelCase extends DisplayNameGenerator.Standard {@Overridepublic String generateDisplayNameForClass(Class<?> testClass) {return replaceCamelCase(super.generateDisplayNameForClass(testClass))+ "...";}@Overridepublic String generateDisplayNameForNestedClass(Class<?> nestedClass) {return replaceCamelCase(super.generateDisplayNameForNestedClass(nestedClass));}@Overridepublic String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {//+ DisplayNameGenerator.parameterTypesAsString(testMethod) 方法的括号return this.replaceCamelCase(testClass.getSimpleName()+ ";方法名:" + testMethod.getName()+ ".");}String replaceCamelCase(String camelCase) {StringBuilder result = new StringBuilder();result.append(camelCase.charAt(0));for (int i=1; i<camelCase.length(); i++) {if (Character.isUpperCase(camelCase.charAt(i))) {result.append(' ');result.append(Character.toLowerCase(camelCase.charAt(i)));} else {result.append(camelCase.charAt(i));}}return result.toString().replace("test","Test");}}}

注意⚠️
- 对应不执行的测试方法的
@BeforeEach和@AfterEach都没有执行 - 如果有描述,显示不执行的描述,如果没有描述内容,显示对应方法名不被执行
@Tag
使用
@Tag注解不但可以放在测试方法上也可以放在测试类的上面。是一个类和方法都可以使用的注解。可以在一个类/方法上有多个,也可以只有一个。
eg :
- 只有一个:
@Tag("decimal") - 有多个:
@Tags({@Tag("decimal"),@Tag("dev")})
命名规范
对应Tag标签的标识名称的命名规范,首先不能是空的字符串,空字符串对应的没有意义,同时标签名称不能有对应的空格及ISO控制字符。
一般情况下,对应的名称都为英文或者是中文来做区分即可。
总结为以下几点:
- 不为空
- 标签不得包含空格
- 标签不得包含 ISO 控制字符。
- 标签不得包含以下任何保留字符
,()&|!
作用
在运行suite套件的时候可以指定对应tag标签来运行特定的类或者方法,只要是对应类或方法上有该标签就会运行。
也可以在pom文件中进行对应group的配置,这样对应的可以只运行特定的方法和类。
总结以上,@Tag注解就是为了特定运行某些方法和类。
总结
- 标记测试
- 测试类或测试方法声明
应用
用例分组
- 环境分组: 测试环境、预发布环境
- 阶段分组: 冒烟用例
- 版本分组: V1.1、V1.2
自定义组成的注释命名
- 接口名随便定义,不一定非要Test结尾
自定义方法上元注释
步骤
- 自定义元注解写在测试方法上
- 生成对应接口文件
- 在接口文件上添加对应注解即可
实现效果
@IntTagTest 替换 @Test+@Tag("integer")- 示例代码
@DisplayName("加法")// @Test// @Tag("integer")@IntTagTestvoid addTest1(){logger.info("Begin Add Test");//加法运算int sum = mySUT.sum(5, 8);logger.info("Operation result:{}",sum);// expected:期望值, actual:运算的实际值assertEquals(13,sum);}
实现代码
package top.testeru.util;import org.junit.jupiter.api.Tag;import org.junit.jupiter.api.Test;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/*** @Package: top.testeru.util* @author: testeru.top* @Description:* @date: 2022年02月09日 3:03 PM*/@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Tag("integer")@Testpublic @interface IntTagTest {}
说明
ElementType.METHOD代表该注解只是在方法上才可以使用RetentionPolicy.RUNTIME注释将由编译器记录在类文件中,并在运行时由VM保留,因此可以反射性地读取它们
自定义类上元注释
步骤
- 自定义元注解写在测试类上
- 生成对应接口文件
- 在接口文件上添加对应注解即可
实现效果
@MyClassTag 替换类上的注解 @Tag("mytag")- 示例代码
@MyClassTagpublic class CommonAnnotation6Test extends BaseTest {...}
实现代码
package top.testeru.util;import org.junit.jupiter.api.Tag;import java.lang.annotation.*;/*** @Package: top.testeru.util* @author: testeru.top* @Description:* @date: 2022年02月09日 3:09 PM*/@Target({ ElementType.TYPE, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Tag("mytag")@Documentedpublic @interface MyClassTag {}
@RepeatedTest
- 想要重复多次的任何测试方法
- 只能添加在测试方法上,和Test使用方法一致
- 方法不能是私有的或静态的,并且返回值必须是void
- ()内为执行的次数
- 方法上有@RepeatedTest则不需要@Test
- 不然真正执行的次数为RepeatedTest的参数值 + 1
package com.testeru.classes;import org.junit.jupiter.api.*;/*** @program: tutorials* @author: testeru.top* @description:* @Version 1.0* @create: 2022/1/7 4:46 下午*/@DisplayName("junit5 test")public class FourDemoTest extends BaseDemoTest{@BeforeAllstatic void beforeAll1(){System.out.println("---进入到首页---");}@BeforeEachvoid beforeEach1(){System.out.println("---搜索商品---");}@DisplayName("first test")@Testvoid test(){System.out.println("---点击查看第 1 个商品详情---");}@DisplayName("second test")@Disabled("先不执行")@Testvoid test2(){System.out.println("---点击查看第 2 个商品详情---");}@DisplayName("third test")@Disabled@Testvoid test3(){System.out.println("---点击查看第 2 个商品详情---");}@DisplayName("five test")@RepeatedTest(3)void test5(){System.out.println("---点击查看第 6 个商品详情---");}@AfterEachvoid afterEach1(){System.out.println("---添加购物车---");}@AfterAllstatic void afterAll1(){System.out.println("---进入购物车列表,生成订单,进行订单付款---");}}

- 相当于重复写了3个相同的方法
- 对应beforeeach和aftereach都会随着重复次数来执行
自定义显示名称
@RepeatedTest(value = 3,name = "Custom name {currentRepetition}/{totalRepetitions}")- value
- 重复执行多少次
- name
- 对应每次执行的自定义名称
currentRepetition:当前重复次数totalRepetitions:重复的总数
- value
package com.testeru.classes;import org.junit.jupiter.api.*;/*** @program: tutorials* @author: testeru.top* @description:* @Version 1.0* @create: 2022/1/7 4:46 下午*/@DisplayName("junit5 test")public class FourDemoTest extends BaseDemoTest{@BeforeAllstatic void beforeAll1(){System.out.println("---进入到首页---");}@BeforeEachvoid beforeEach1(){System.out.println("---搜索商品---");}@DisplayName("first test")@Testvoid test(){System.out.println("---点击查看第 1 个商品详情---");}@DisplayName("second test")@Disabled("先不执行")@Testvoid test2(){System.out.println("---点击查看第 2 个商品详情---");}@DisplayName("third test")@Disabled@Testvoid test3(){System.out.println("---点击查看第 2 个商品详情---");}@DisplayName("five test")@RepeatedTest(value = 3,name = "Custom name {currentRepetition}/{totalRepetitions}")void test5(){System.out.println("---点击查看第 6 个商品详情---");}@AfterEachvoid afterEach1(){System.out.println("---添加购物车---");}@AfterAllstatic void afterAll1(){System.out.println("---进入购物车列表,生成订单,进行订单付款---");}}

方法内调用
- 方法内想要知道调用当前是第几次重复和总共重复的次数
@RepeatedTest(value = 3,name = "Custom name {currentRepetition}/{totalRepetitions}")void test4(RepetitionInfo repetitionInfo) {int currentRepetition = repetitionInfo.getCurrentRepetition();System.out.println("第" + currentRepetition +"次搜索 查看第 " + currentRepetition + "个商品详情");}

- 测试方法不是
@RepeatedTest,则不能将RepetitionInfo注入到@BeforeEach或@AfterEach方法中
package com.testeru.classes;import org.junit.jupiter.api.*;/*** @program: tutorials* @author: testeru.top* @description:* @Version 1.0* @create: 2022/1/7 4:46 下午*/@DisplayName("junit5 test")public class FiveDemoTest{@BeforeEachvoid beforeEach1(RepetitionInfo repetitionInfo){int currentRepetition = repetitionInfo.getCurrentRepetition();System.out.println("---搜索商品---" + currentRepetition);}@AfterEachvoid afterEach1(RepetitionInfo repetitionInfo){int currentRepetition = repetitionInfo.getCurrentRepetition();System.out.println("---添加购物车---"+ currentRepetition);}@DisplayName("four test")@RepeatedTest(value = 3,name = "重复搜索次数 {currentRepetition}/{totalRepetitions}")void test4(RepetitionInfo repetitionInfo) {int currentRepetition = repetitionInfo.getCurrentRepetition();System.out.println("第" + currentRepetition +"次搜索 查看第 " + currentRepetition + "个商品详情");}@DisplayName("third test")@Testvoid test3(){System.out.println("---点击查看第 2 个商品详情---");}@DisplayName("first test")@RepeatedTest(2)void test1(){System.out.println("---点击查看第 1 个商品详情---");}}
报错:
org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [org.junit.jupiter.api.RepetitionInfo arg0] in method [void com.testeru.classes.FiveDemoTest.beforeEach1(org.junit.jupiter.api.RepetitionInfo)].

