「译」JUnit 5 系列:条件测试
原文地址:http://blog.codefx.org/libraries/junit-5-conditions/
原文日期:08, May, 2016
译文首发:Linesh 的博客:「译」JUnit 5 系列:条件测试
我的 Github:http://github.com/linesh-simplicity
上一节我们了解了 JUnit 新的扩展模型,了解了它是如何支持我们向引擎定制一些行为的。然后我还预告会为大家讲解条件测试,这一节主题就是它了。
条件测试,指的是允许我们自定义灵活的标准,来决定一个测试是否应该执行。条件(condition) 官方的叫法是条件测试执行。
概述
(如果不喜欢看文章,你可以戳这里看我的演讲,或者看一下最近的 vJUG 讲座,或者我在 DevoxxPL 上的 PPT。
本系列文章都基于 Junit 5发布的先行版 Milestone 2。它可能会有变化。如果有新的里程碑(milestone)版本发布,或者试用版正式发行时,我会再来更新这篇文章。
这里要介绍的多数知识你都可以在 JUnit 5 用户指南 中找到(这个链接指向的是先行版 Milestone 2,想看的最新版本文档的话请戳这里),并且指南还有更多的内容等待你发掘。下面的所有代码都可以在 我的 Github 上找到。
目录
- 相关的扩展点
- 动手实现一个@Disabled 注解
- @DisabledOnOs
- 一种简单的实现方式
- 更简洁的API
- 代码重构
- @DisabledIfTestFails
- 异常收集
- 禁用测试
- 集成
- 回顾总结
- 分享&关注
相关的扩展点
还记得 拓展点 一节讲的内容吗?不记得了?好吧,简单来说,JUnit 5 中定义了许多扩展点,每个扩展点都对应一个接口。你自己的扩展可以实现其中的某些接口,然后通过 @ExtendWith 注解注册给 JUnit,后者会在特定的时间点调用你的接口实现。
要实现条件测试,你需要关注其中的两个扩展点: ContainerExecutionCondition (容器执行条件)和 TestExecutionCondition (测试执行条件)。
public interface ContainerExecutionCondition extends Extension {
/**
* Evaluate this condition for the supplied ContainerExtensionContext.
*
* An enabled result indicates that the container should be executed;
* whereas, a disabled result indicates that the container should not
* be executed.
*
* @param context the current ContainerExtensionContext; never null
* @return the result of evaluating this condition; never null
*/
ConditionEvaluationResult evaluate(ContainerExtensionContext context);
}
public interface TestExecutionCondition extends Extension {
/**
* Evaluate this condition for the supplied TestExtensionContext.
*
* An enabled result indicates that the test should be executed;
* whereas, a disabled result indicates that the test should not
* be executed.
*
* @param context the current TestExtensionContext; never null
* @return the result of evaluating this condition; never null
*/
ConditionEvaluationResult evaluate(TestExtensionContext context);
}
ContainerExecutionCondition 接口将决定容器中的测试是否会被执行。通常情况下,你使用 @Test 注解来标记测试,此时测试所在的类就是容器。同时,单独的测试方法是否执行则是由 TestExecutionCondition 接口决定的。
(这里,我说的是“通常情况下”,因为其他测试引擎可能对容器和测试有截然不同的定义。但一般情况下,测试就是单个的方法,容器指的就是测试类。)
嗯,基本知识就这么多。想实现条件测试,至少需要实现以上两个接口中的一个,并在接口的 evalute 方法中执行自己的条件检查。
动手实现一个@Disabled 注解
最简单的“条件”就是判断都没有,直接禁用测试。如果在方法上发现了 @Disabled 注解,我们就直接禁用该测试。
让我们来写一个这样的 @Disabled 注解吧:
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(@DisabledCondition.class)
public @interface Disabled { }
对应的扩展如下:
public class DisabledCondition
implements ContainerExecutionCondition, TestExecutionCondition {
private static final ConditionEvaluationResult ENABLED =
ConditionEvaluationResult.enabled("@Disabled is not present");
@Override
public ConditionEvaluationResult evaluate(
ContainerExtensionContext context) {
return evaluateIfAnnotated(context.getElement());
}
@Override
public ConditionEvaluationResult evaluate(
TestExtensionContext context) {
return evaluateIfAnnotated(context.getElement());
}
private ConditionEvaluationResult evaluateIfAnnotated(
Optional<AnnotatedElement> element) {
Optional<Disabled> disabled = AnnotationUtils
.findAnnotation(element, Disabled.class);
if (disabled.isPresent())
return ConditionEvaluationResult
.disabled(element + " is @Disabled");
return ENABLED;
}
}
写起来小菜一碟吧?在 JUnit 真实的产品代码中,@Disabled 也是这么实现的。不过,有两个地方有一些细微的差别:
- 官方
@Disabled注解不需要再使用@ExtendWith注册扩展,因为它是默认注册了的 - 官方
@Disabled注解可以接收一个参数,解释测试被忽略的理由。它会在测试被忽略时被记录下来
使用时请注意,AnnotationUtils 是个内部 API。不过,官方可能很快就会将它提供的功能给开放出来。
接下来让我们写点更有意思的东西吧。
@DisabledOnOs
如果有些测试我们只想让它在特定的操作系统上面运行,这个要怎么实现呢?
一种简单的实现方式
当然,我们还是从注解开始咯:
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(OsCondition.class)
public @interface DisabledOnOs {
OS[] value() default {};
}
这回注解需要接收一个或多个参数值,你需要告诉它想禁用测试的操作系统有哪些。 OS 是个枚举类,定义了所有操作系统的名字。同时,它还提供了一个静态的 static OS determine() 方法,你可能已经从名字猜到了,它会推断并返回你当前所用的操作系统。
现在我们可以着手实现 OsCondition 扩展类了。它必须检查两点:注解是否存在,以及当前操作系统是否在注解声明的禁用列表中。
public class OsCondition
implements ContainerExecutionCondition, TestExecutionCondition {
// both `evaluate` methods forward to `evaluateIfAnnotated` as above
private ConditionEvaluationResult evaluateIfAnnotated(
Optional<AnnotatedElement> element) {
Optional<DisabledOnOs> disabled = AnnotationUtils
.findAnnotation(element, DisabledOnOs.class);
if (disabled.isPresent())
return disabledIfOn(disabled.get().value());
return ENABLED;
}
private ConditionEvaluationResult disabledIfOn(OS[] disabledOnOs) {
OS os = OS.determine();
if (Arrays.asList(disabledOnOs).contains(os))
return ConditionEvaluationResult
.disabled("Test is disabled on " + os + ".");
else
return ConditionEvaluationResult
.enabled("Test is not disabled on " + os + ".");
}
}
然后使用的时候就可以像这样:
@Test
@DisabledOnOs(OS.WINDOWS)
void doesNotRunOnWindows() {
assertTrue(false);
}
棒。
更简洁的API
但代码还可以写得更好!JUnit 的注解是可组合的,基于此我们可以让这个条件注解更简洁:
@TestExceptOnOs(OS.WINDOWS)
void doesNotRunOnWindowsEither() {
assertTrue(false);
}
@TestExceptionOnOs完美的实现方案是这样的:
@Retention(RetentionPolicy.RUNTIME)
@Test
@DisabledOnOs(/* 通过某种方式取得注解下的 `value` 值 */)
public @interface TestExceptOnOs {
OS[] value() default {};
}
测试实际运行时, OsCondition::evaluateIfAnnotated 方法会扫描 @DisabledOnOs 注解,然后我们发现它又是对 @TestExceptOnOs 的注解,前面写的代码就可以如期工作了。但我不知道如何在 @DisabledOnOs 注解中获取 @TestExceptOnOs 中的value()值。
「译」JUnit 5 系列:条件测试的更多相关文章
- 「译」JUnit 5 系列:扩展模型(Extension Model)
原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...
- 「译」JUnit 5 系列:环境搭建
原文地址:http://blog.codefx.org/libraries/junit-5-setup/ 原文日期:15, Feb, 2016 译文首发:Linesh 的博客:环境搭建 我的 Gith ...
- 「译」JUnit 5 系列:架构体系
原文地址:http://blog.codefx.org/design/architecture/junit-5-architecture/ 原文日期:29, Mar, 2016 译文首发:Linesh ...
- 「译」JUnit 5 系列:基础入门
原文地址:http://blog.codefx.org/libraries/junit-5-basics/ 原文日期:25, Feb, 2016 译文首发:Linesh 的博客:JUnit 5 系列: ...
- jvm系列(十):如何优化Java GC「译」
本文由CrowHawk翻译,是Java GC调优的经典佳作. 本文翻译自Sangmin Lee发表在Cubrid上的"Become a Java GC Expert"系列文章的第三 ...
- jvm系列(七):如何优化Java GC「译」
本文由CrowHawk翻译,地址:如何优化Java GC「译」,是Java GC调优的经典佳作. Sangmin Lee发表在Cubrid上的”Become a Java GC Expert”系列文章 ...
- 「译」JavaScript 的怪癖 1:隐式类型转换
原文:JavaScript quirk 1: implicit conversion of values 译文:「译」JavaScript 的怪癖 1:隐式类型转换 译者:justjavac 零:提要 ...
- iOS 9,为前端世界都带来了些什么?「译」 - 高棋的博客
2015 年 9 月,Apple 重磅发布了全新的 iPhone 6s/6s Plus.iPad Pro 与全新的操作系统 watchOS 2 与 tvOS 9(是的,这货居然是第 9 版),加上已经 ...
- 「译」forEach循环中你不知道的3件事
前言 本文925字,阅读大约需要7分钟. 总括: forEach循环中你不知道的3件事. 原文地址:3 things you didn't know about the forEach loop in ...
随机推荐
- Tomcat一个BUG造成CLOSE_WAIT
之前应该提过,我们线上架构整体重新架设了,应用层面使用的是Spring Boot,前段日子因为一些第三方的原因,略有些匆忙的提前开始线上的内测了.然后运维发现了个问题,服务器的HTTPS端口有大量的C ...
- wordpress多站点配置
wordpress作为全球第一的个人博客搭建平台一直在国内外有着较高的人气,从3.0版本开始就已经支持多站点的搭建.该功能可以让子站点运行主站点的程序,不需要再每个站点分别存放网站程序.最近更新的4. ...
- 移动先行之谁主沉浮? 带着你的Net飞奔吧!
移动系源码:https://github.com/dunitian/Windows10 移动系文档:https://github.com/dunitian/LoTDotNet/tree/master/ ...
- 【.net 深呼吸】限制执行代码的权限
前面好几篇文章,老周都跟大伙伴们聊了跟应用程序域有关的话题,干脆咱们一聊到底吧,做学问就应该这样,有恒心. App Domain的创建新应用程序域的方法中,有一个特殊的重载: public stati ...
- javascript工厂模式和构造函数模式创建对象
一.工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程(本书后面还将讨论其他设计模式及其在JavaScript 中的实现).考虑到在ECMAScript 中无法创 ...
- 【NLP】干货!Python NLTK结合stanford NLP工具包进行文本处理
干货!详述Python NLTK下如何使用stanford NLP工具包 作者:白宁超 2016年11月6日19:28:43 摘要:NLTK是由宾夕法尼亚大学计算机和信息科学使用python语言实现的 ...
- 利用注册表在右键添加VS15的快捷方式打开文件夹
1.简介 最近安装VS15 Preview 5,本版本可以打开"文件夹" 是否可以向Visual Studio Code一样在文件夹或文件右键菜单添加"Open with ...
- Java实现FTP文件与文件夹的上传和下载
Java实现FTP文件与文件夹的上传和下载 FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为"文传协议".用于Internet上的控制 ...
- windows charles response 乱码解决办法
使用windows 版本的charles来做代理,发现服务端返回的response会出现中文乱码的情况, 查看软件设置,遗憾的是并没有关于编码的选项. 好在charles windows版本安装目录下 ...
- JBPM
JBPM简介 什么是jbpm JBPM,全称是Java Business Process Management(业务流程管理),它是覆盖了业务流程管理.工作流.服务协作等领域的一个开源的.灵活的.易扩 ...