document.addeventlistener方法不执行_JUnit 5 测试方法的执行优先级
前言
使用單元測(cè)試有時(shí)對(duì)方法的執(zhí)行順序有要求,而默認(rèn)情況下測(cè)試方法的執(zhí)行并非按照編寫(xiě)順序,這就導(dǎo)致測(cè)試用例因執(zhí)行順序而導(dǎo)致的不通過(guò)。這里我使用的JUnit版本是5.6.2,下面講述如何自定義測(cè)試方法的執(zhí)行優(yōu)先級(jí)。
@TestMethodOrder
這個(gè)注解標(biāo)注在測(cè)試類(lèi)上,用于指定測(cè)試方法要以怎樣的方式確定執(zhí)行順序:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface TestMethodOrder {Class<? extends MethodOrderer> value(); }value()接收一個(gè)MethodOrderer類(lèi)型,這個(gè)類(lèi)型是一個(gè)接口,里面重要的有一個(gè)接口方法orderMethods以及三個(gè)靜態(tài)實(shí)現(xiàn)類(lèi),分別是:Random、OrderAnnotation、Alphanumeric:
public interface MethodOrderer {void orderMethods(MethodOrdererContext context);default Optional<ExecutionMode> getDefaultExecutionMode() {return Optional.of(ExecutionMode.SAME_THREAD);}// 隨機(jī)順序class Random implements MethodOrderer {// ...}// 根據(jù)@Order注解確定執(zhí)行順序,注意這個(gè)注解在org.junit.jupiter.api包下class OrderAnnotation implements MethodOrderer {// ...}// 按照方法名字母升序順序,如果方法名相同,則拿方法的參數(shù)列表類(lèi)型名稱(chēng)比較class Alphanumeric implements MethodOrderer {// ...} }其中比較重要的是void orderMethods(MethodOrdererContext context);接口方法,如果你不滿(mǎn)足于默認(rèn)提供的三種實(shí)現(xiàn),可以實(shí)現(xiàn)此方法,方法參數(shù)MethodOrdererContext可以獲得測(cè)試方法的上下文信息,據(jù)此定制方法執(zhí)行順序。一般來(lái)說(shuō)上述提供的三種實(shí)現(xiàn)已基本滿(mǎn)足需求,有需要可參照三種實(shí)現(xiàn)。
Random
隨機(jī)確定方法執(zhí)行順序,只需要在測(cè)試類(lèi)上標(biāo)注如下:
@TestMethodOrder(MethodOrderer.Random.class) class SampleTests {// methods ... }以下是Random的關(guān)鍵源碼:
class Random implements MethodOrderer {private static final long DEFAULT_SEED;static {DEFAULT_SEED = System.nanoTime(); // 默認(rèn)的隨機(jī)種子是系統(tǒng)時(shí)間,單位納秒}public static final String RANDOM_SEED_PROPERTY_NAME = "junit.jupiter.execution.order.random.seed"; // 在配置文件中指定隨機(jī)種子,這個(gè)值必須是數(shù)值型@Overridepublic void orderMethods(MethodOrdererContext context) {// 對(duì)方法隨機(jī)洗牌Collections.shuffle(context.getMethodDescriptors(),new java.util.Random(getCustomSeed(context).orElse(DEFAULT_SEED)));}// 獲取配置文件中指定的隨機(jī)種子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
如果需要為特定的方法指定執(zhí)行順序,需要在測(cè)試類(lèi)上標(biāo)注@TestMethodOrder(MethodOrderer.OrderAnnotation.class) ,這個(gè)注解不能夠單獨(dú)使用,需要配合方法上的注解org.junit.jupiter.api.Order確定執(zhí)行順序,你可以只為希望按順序執(zhí)行的方法標(biāo)注此注解,而不是所有方法:
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) class SampleTests {@Test@Order(1) // 優(yōu)先執(zhí)行void shouldUploadFileSuccess() throws Exception {}@Test@Order(2) // 延后執(zhí)行void shouldDeleteFileSuccess() throws Exception {}@Test // 不會(huì)因執(zhí)行順序而導(dǎo)致失敗,可不指定@Ordervoid shouldListAllFiles() throws Exception {} }@Order注解中的value越小越優(yōu)先執(zhí)行,沒(méi)有標(biāo)注@Order的方法使用的是DEFAULT值:
@Target({ ElementType.FIELD, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Order {int DEFAULT = Integer.MAX_VALUE / 2;int value(); }下面是OrderAnnotation實(shí)現(xiàn):
class OrderAnnotation implements MethodOrderer {@Overridepublic void orderMethods(MethodOrdererContext context) {// java.util.Comparator.comparingIntcontext.getMethodDescriptors().sort(comparingInt(OrderAnnotation::getOrder));}// 獲取方法上@Order注解的value,沒(méi)有標(biāo)注@Order注解的方法使用的是@Order注解上的DEFAULT值private static int getOrder(MethodDescriptor descriptor) {return descriptor.findAnnotation(Order.class).map(Order::value).orElse(Order.DEFAULT);}}方法排序表面使用的是Comparator接口的靜態(tài)方法comparingInt,實(shí)際使用的是java.lang.Integer.compare的比較邏輯:
public static int compare(int x, int y) {return (x < y) ? -1 : ((x == y) ? 0 : 1);}Alphanumeric
按照方法名的字母升序排序執(zhí)行,如果方法名相同,則拿方法的參數(shù)列表類(lèi)型名稱(chēng)比較:
@TestMethodOrder(MethodOrderer.Alphanumeric.class) class AlphaTests {@Test // 后執(zhí)行void b() {}@Test // 先執(zhí)行void a() {} }下面是這種方式的實(shí)現(xiàn):
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())// 如果測(cè)試方法的名稱(chēng)相同,則進(jìn)一步比較方法上的參數(shù)列表的類(lèi)型.thenComparing(descriptor -> parameterList(descriptor.getMethod()));// 將方法的參數(shù)列表類(lèi)型處理成形如:java.lang.String,java.lang.Integerdprivate static String parameterList(Method method) {return ClassUtils.nullSafeToString(method.getParameterTypes());}}上面parameterList方法用到的ClassUtils是JUnit自身的,實(shí)際并沒(méi)什么可看,就是對(duì)給定的類(lèi)型列表名稱(chēng)做逗號(hào)拼接處理(使用的是Java 8中的函數(shù)式編程,自行了解):
public final class ClassUtils {private ClassUtils() {}public static String nullSafeToString(Class<?> clazz) {return clazz == null ? "null" : clazz.getName();}// method.getParameterTypes()得到的是一個(gè)數(shù)組,所以使用的的是這個(gè)方法public static String nullSafeToString(Class<?>... classes) {// Class:getName => clazz -> clazz.getNamereturn nullSafeToString(Class::getName, classes);}// Function<? super Class<?>, ? extends String> mapper表示傳入的是一個(gè)Class類(lèi)型,// 將會(huì)產(chǎn)生一個(gè)String類(lèi)型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)將調(diào)用nullSafeToString(Class::getName, classes)// 中的Class::getName用于獲取類(lèi)型限定名稱(chēng)return clazz == null ? "null" : (String)mapper.apply(clazz);}).collect(Collectors.joining(", ")) : "";} }軟件版本
| JUnit | 5.6.2(junit-jupiter) |
總結(jié)
以上是生活随笔為你收集整理的document.addeventlistener方法不执行_JUnit 5 测试方法的执行优先级的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: node --- [跨域] 预检请求
- 下一篇: 在ArcMap离线加载海量卫星影像的方法