前言

使用单元测试有时对方法的执行顺序有要求,而默认情况下测试方法的执行并非按照编写顺序,这就导致测试用例因执行顺序而导致的不通过。这里我使用的JUnit版本是5.6.2,下面讲述如何自定义测试方法的执行优先级。

@TestMethodOrder

这个注解标注在测试类上,用于指定测试方法要以怎样的方式确定执行顺序:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface TestMethodOrder {Class<? extends MethodOrderer> value();
}

value()接收一个MethodOrderer类型,这个类型是一个接口,里面重要的有一个接口方法orderMethods以及三个静态实现类,分别是:RandomOrderAnnotationAlphanumeric

public interface MethodOrderer {void orderMethods(MethodOrdererContext context);default Optional<ExecutionMode> getDefaultExecutionMode() {return Optional.of(ExecutionMode.SAME_THREAD);}// 随机顺序class Random implements MethodOrderer {// ...}// 根据@Order注解确定执行顺序,注意这个注解在org.junit.jupiter.api包下class OrderAnnotation implements MethodOrderer {// ...}// 按照方法名字母升序顺序,如果方法名相同,则拿方法的参数列表类型名称比较class Alphanumeric implements MethodOrderer {// ...}
}

其中比较重要的是void orderMethods(MethodOrdererContext context);接口方法,如果你不满足于默认提供的三种实现,可以实现此方法,方法参数MethodOrdererContext可以获得测试方法的上下文信息,据此定制方法执行顺序。一般来说上述提供的三种实现已基本满足需求,有需要可参照三种实现。

Random

随机确定方法执行顺序,只需要在测试类上标注如下:

@TestMethodOrder(MethodOrderer.Random.class)
class SampleTests {// methods ...
}

以下是Random的关键源码:

class Random implements MethodOrderer {private static final long DEFAULT_SEED;static {DEFAULT_SEED = System.nanoTime(); // 默认的随机种子是系统时间,单位纳秒}public static final String RANDOM_SEED_PROPERTY_NAME = "junit.jupiter.execution.order.random.seed"; // 在配置文件中指定随机种子,这个值必须是数值型@Overridepublic void orderMethods(MethodOrdererContext context) {// 对方法随机洗牌Collections.shuffle(context.getMethodDescriptors(),new java.util.Random(getCustomSeed(context).orElse(DEFAULT_SEED)));}// 获取配置文件中指定的随机种子private Optional<Long> getCustomSeed(MethodOrdererContext context) {return context.getConfigurationParameter(RANDOM_SEED_PROPERTY_NAME).map(configurationParameter -> {Long seed = null;try {seed = Long.valueOf(configurationParameter);}catch (NumberFormatException ex) {}return seed;});}}

OrderAnnotation

如果需要为特定的方法指定执行顺序,需要在测试类上标注@TestMethodOrder(MethodOrderer.OrderAnnotation.class) ,这个注解不能够单独使用,需要配合方法上的注解org.junit.jupiter.api.Order确定执行顺序,你可以只为希望按顺序执行的方法标注此注解,而不是所有方法:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class SampleTests {@Test@Order(1) // 优先执行void shouldUploadFileSuccess() throws Exception {}@Test@Order(2) // 延后执行void shouldDeleteFileSuccess() throws Exception {}@Test // 不会因执行顺序而导致失败,可不指定@Ordervoid shouldListAllFiles() throws Exception {}
}

@Order注解中的value越小越优先执行,没有标注@Order的方法使用的是DEFAULT值:

@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Order {int DEFAULT = Integer.MAX_VALUE / 2;int value();
}

下面是OrderAnnotation实现:

class OrderAnnotation implements MethodOrderer {@Overridepublic void orderMethods(MethodOrdererContext context) {// java.util.Comparator.comparingIntcontext.getMethodDescriptors().sort(comparingInt(OrderAnnotation::getOrder));}// 获取方法上@Order注解的value,没有标注@Order注解的方法使用的是@Order注解上的DEFAULT值private static int getOrder(MethodDescriptor descriptor) {return descriptor.findAnnotation(Order.class).map(Order::value).orElse(Order.DEFAULT);}}

方法排序表面使用的是Comparator接口的静态方法comparingInt,实际使用的是java.lang.Integer.compare的比较逻辑:

public static int compare(int x, int y) {return (x < y) ? -1 : ((x == y) ? 0 : 1);}

Alphanumeric

按照方法名的字母升序排序执行,如果方法名相同,则拿方法的参数列表类型名称比较:

@TestMethodOrder(MethodOrderer.Alphanumeric.class)
class AlphaTests {@Test // 后执行void b() {}@Test // 先执行void a() {}
}

下面是这种方式的实现:

class Alphanumeric implements MethodOrderer {@Overridepublic void orderMethods(MethodOrdererContext context) {context.getMethodDescriptors().sort(comparator);}private static final Comparator<MethodDescriptor> comparator = Comparator.<MethodDescriptor, String>// 拿方法名比较 comparing(descriptor -> descriptor.getMethod().getName())// 如果测试方法的名称相同,则进一步比较方法上的参数列表的类型.thenComparing(descriptor -> parameterList(descriptor.getMethod()));// 将方法的参数列表类型处理成形如:java.lang.String,java.lang.Integerdprivate static String parameterList(Method method) {return ClassUtils.nullSafeToString(method.getParameterTypes());}}

上面parameterList方法用到的ClassUtilsJUnit自身的,实际并没什么可看,就是对给定的类型列表名称做逗号拼接处理(使用的是Java 8中的函数式编程,自行了解):

public final class ClassUtils {private ClassUtils() {}public static String nullSafeToString(Class<?> clazz) {return clazz == null ? "null" : clazz.getName();}// method.getParameterTypes()得到的是一个数组,所以使用的的是这个方法public static String nullSafeToString(Class<?>... classes) {// Class:getName => clazz -> clazz.getNamereturn nullSafeToString(Class::getName, classes);}// Function<? super Class<?>, ? extends String> mapper表示传入的是一个Class类型,// 将会产生一个String类型public static String nullSafeToString(Function<? super Class<?>, ? extends String> mapper, Class<?>... classes) {Preconditions.notNull(mapper, "Mapping function must not be null");return classes != null && classes.length != 0 ? (String)Arrays.stream(classes).map((clazz) -> {// mapper.apply(clazz)将调用nullSafeToString(Class::getName, classes)// 中的Class::getName用于获取类型限定名称return clazz == null ? "null" : (String)mapper.apply(clazz);}).collect(Collectors.joining(", ")) : "";}
}

软件版本

软件 版本
JUnit 5.6.2(junit-jupiter)

document.addeventlistener方法不执行_JUnit 5 测试方法的执行优先级相关推荐

  1. HTML5+ document.addEventListener('plusready'不执行解决办法!!!

    // 这里可以调用5+ API了,为了更好的兼容性,应该使用以下代码进行判断 if(window.plus){ // 在这里调用5+ API }else{// 兼容老版本的plusready事件 do ...

  2. JS:attachEvent和addEventListener方法

    <SCRIPT LANGUAGE="JavaScript"> <!--     /**************************************** ...

  3. HTML DOM addEventListener() 方法

    实例 为 <button> 元素添加点击事件. 当用户点击按钮时,在 id="demo" 的 <p> 元素上输出 "Hello World&quo ...

  4. addEventListener方法与on事件的区别

    文章出自个人博客https://knightyun.github.io/2018/05/31/js-eventlistener,转载请申明 on事件 Javascript中可以对一些页面的事件设定触发 ...

  5. document.addEventListener理解

    document.addEventListener("事件名称", 函数, false); function 某函数(event){ //  方法执行 } addEventList ...

  6. document.addEventListener的使用介绍

    document.addEventListener("事件名称", 函数, false); function 函数名(event){ // 方法执行 } addEventListe ...

  7. addEventListener() 方法

    说明: addEventListener() 方法用于向指定元素添加监听事件.且同一元素目标可重复添加,不会覆盖之前相同事件,配合 removeEventListener() 方法来移除事件. 使用方 ...

  8. addEventListener方法

    addEventListener()方法 这个方法设定一个事件监听器,当某一事件发生通过设定的参数执行操作.语法是: addEventListener(event, function, useCapt ...

  9. document.addEventListener

    document.addEventListener("事件名称", 函数, false); function 某函数(event){ //  方法执行 } addEventList ...

最新文章

  1. Numpy入门教程:10. 统计相关
  2. qt icon如何显示gif_收集Qt支持的emoji表情-第五弹
  3. 《剑指offer》-- 栈的压入与弹出序列、把字符串转化为整数、扑克牌顺子、孩子们的游戏(圆圈中最后剩下的数)
  4. 软件工程综合实践专题第三次个人博客作业
  5. 【OSG】OSG软件模块结构
  6. 详解站长之家之站长工具四大新功能
  7. 关于 FAT12 文件系统
  8. 如何在 R 中 计算 t 临界值
  9. java连接微信发送给好友信息,微信消息转发以及给指定好友发送消息
  10. 解决最新版搜狗输入法的软键盘快捷键Ctrl + Shift + K和Typora的热键冲突问题
  11. 【Cadence17.2】Padstack Editor制作焊盘和过孔
  12. 同花顺l2数据接口到底有什么用?
  13. 03-JSX的语法规则
  14. matlab多条曲线绘制在一张表格——设置绘图曲线类型、plot设置名称、坐标轴范围和精度
  15. 历届试题 核桃的数量(3个数的最小公倍数),翻硬币(贪心),买不到的数目(在范围内暴力,找范围,最小公倍数是上界,最小的数是下界),兰顿蚂蚁(dfs,模拟)
  16. dns被污染后应该怎么办?
  17. python开发视频播放器_Python实现的视频播放器功能完整示例
  18. nacos 配置Sentinel 熔断规则
  19. 【Leetcode】312. Burst Balloons
  20. iMeta | 中科院南京土壤所吴永红组揭示周丛生物非生物成分的地理印记和生态功能...

热门文章

  1. 模拟微信自动化发送(微信公众号文章自动点击)
  2. Will not attempt to authenticate using SASL | dubbo项目启动特别慢,拉取 zookeeper 服务日志打印特别慢
  3. laydate根据开始时间或者结束时间限制范围
  4. spring框架中@PostConstruct的实现原理
  5. 1070. 结绳(25)
  6. 计算机英语 传输介质,计算机英语实用教程unit7
  7. (JAVA)CollectionDemo3
  8. 现代计算机应用特点,现代计算机的特点和计算机的发展
  9. C# Json转对象
  10. hdu4554 A Famous Game 概率期望