JUnit规则

第一次偶然发现JUnit @Rule批注时,我对此概念有些恼火。 在测试用例中拥有一个公共领域似乎有些奇怪,因此我不愿意定期使用它。 但是一段时间后,我习惯了这一点,事实证明,规则可以通过多种方式简化编写测试的过程。 这篇文章简要介绍了该概念,并简要列举了一些规则的优点。

什么是JUnit规则?

让我们从一个现成的JUnit规则开始。 TemporaryFolder是一个测试帮助程序,可用于为临时内容1创建位于文件系统目录下的文件和文件夹。 TemporaryFolder的有趣之处在于,它保证在测试方法完成时删除其文件和文件夹2 。 为了按预期方式工作,必须将临时文件夹实例分配给@Rule注释字段,该字段必须是公共的(不是静态的),并且是TestRule的子类型:

public class MyTest {@Rulepublic TemporaryFolder temporaryFolder = new TemporaryFolder();@Testpublic void testRun() throws IOException {assertTrue( temporaryFolder.newFolder().exists() );}
}


它是如何工作的?

规则提供了一种拦截测试方法调用的可能性,就像AOP框架一样。 与AspectJ中的周围建议相比,您可以在实际测试执行之前和/或之后做一些有用的事情3 。 尽管这听起来很复杂,但是却很容易实现。

规则定义的API部分必须实现TestRule。 此接口称为apply的唯一方法返回StatementStatement s表示(简单地说)在JUnit运行时中的测试,而Statement#evaluate()执行它们。 现在,基本思想是提供Statement包装扩展,该包装可以通过覆盖Statement#evaluate()来进行实际贡献:

public class MyRule implements TestRule {@Overridepublic Statement apply( Statement base, Description description ) {return new MyStatement( base );}
}public class MyStatement extends Statement {private final Statement base;public MyStatement( Statement base ) {this.base = base;}@Overridepublic void evaluate() throws Throwable {System.out.println( 'before' );try {base.evaluate();} finally {System.out.println( 'after' );}}
}

MyStatement作为包装器实现,在MyRule#apply(Statement,Destination)使用该包装器包装作为参数给出的原始语句。 很容易看出,包装程序覆盖了Statement#evaluate()在实际测试4之前和之后做一些事情。

下一个代码片段显示如何与上面的TemporaryFolder完全一样地使用MyRule

public class MyTest {@Rulepublic MyRule myRule = new MyRule();@Testpublic void testRun() {System.out.println( 'during' );}
}

启动测试用例将导致以下控制台输出,这证明我们的示例规则可以按预期工作。 测试执行被我们的规则拦截和修改,以在测试的“期间”前后打印“之前”和“之后”:

before
during
after

现在已经了解了基础知识,下面让我们看一下您可以使用规则执行的更有用的事情。

测试治具

从相应的维基百科部分引用的“测试装置”是运行测试并期望获得特定结果所必须具备的所有条件。 通常,通过处理单元测试框架的setUp()tearDown()事件来创建固定装置。

使用JUnit,这通常看起来像这样:

public class MyTest {private MyFixture myFixture;@Testpublic void testRun1() {myFixture.configure1();// do some testing here}@Testpublic void testRun2() {myFixture.configure2();// do some testing here}@Beforepublic void setUp() {myFixture = new MyFixture();}@Afterpublic void tearDown() {myFixture.dispose();}
}

考虑您在许多测试中以上面显示的方式使用特定的夹具。 在那种情况下,最好摆脱setUp()tearDown()方法。 鉴于以上各节,我们现在知道可以通过更改MyFixture来实现TestRule来完成。 适当的Statement实现必须确保它调用MyFixture#dispose()并且看起来可能像这样:

public class MyFixtureStatement extends Statement {private final Statement base;private final MyFixture fixture;public MyFixtureStatement( Statement base, MyFixture fixture ) {this.base = base;this.fixture = fixture;}@Overridepublic void evaluate() throws Throwable {try {base.evaluate();} finally {fixture.dispose();}}
}

有了这个,上面的测试可以重写为:

public class MyTest {@Rulepublic MyFixture myFixture = new MyFixture();@Testpublic void testRun1() {myFixture.configure1();// do some testing here}@Testpublic void testRun2() {myFixture.configure2();// do some testing here}
}

在很多情况下,我开始欣赏使用规则编写测试的更为紧凑的形式,但是可以肯定的是,这也是一个品味问题以及您认为更适合阅读的内容5

带有方法注释的夹具配置

到目前为止,我已默默地忽略了TestRule#apply(Statement,Description)Description参数。 通常, Description描述了将要运行或已经运行的测试。 但它也允许访问有关底层java方法的一些反射信息。 除其他外,有可能读取这种方法附带的注释。 这使我们能够将规则与方法注释结合起来,以方便配置TestRule

考虑以下注释类型:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Configuration {String value();
}

MyFixture#apply(Statement,Destination)中的以下代码段结合使用,该代码读取注释为特定测试方法的配置值…

Configuration annotation= description.getAnnotation( Configuration.class );
String value = annotation.value();
// do something useful with value

…上面演示MyFixture规则用法的MyFixture可以重写为:

public class MyTest {@Rulepublic MyFixture myFixture = new MyFixture();@Test@Configuration( value = 'configuration1' )public void testRun1() {// do some testing here}@Test@Configuration( value = 'configuration2' )public void testRun2() {// do some testing here}
}

当然,由于注释仅允许EnumClass es或String文字作为参数,因此后一种方法存在局限性。 但是在某些用例中,这已经足够了。 restfuse库提供了一个很好的示例,该示例将规则与方法注释结合使用。 如果您对现实世界的示例感兴趣,则应查看Destination规则6的库实现。

最后,剩下的唯一要说的是,我很想听听您关于可以用来简化日常测试工作的JUnit规则的其他有用示例的信息:

  1. 通常由System.getProperty( 'java.io.tmpdir' );返回的目录System.getProperty( 'java.io.tmpdir' );
  2. 在查看TemporaryFolder的实现时,我必须注意,它不会检查文件删除是否成功。 这可能是打开的文件句柄的情况下,一个薄弱点↩
  3. 值得的是,您甚至可以用其他方法代替完整的测试方法↩
  4. 包装语句的委托放入try...finally块中,以确保执行测试后的功能,即使测试失败。 在这种情况下,一个AssertionError会被抛出,并且不是在finally块语句都将跳过↩
  5. 你可能注意到TemporaryFolder之初例子也不外乎夹具的使用情况↩
  6. 请注意,restfuse的Destination类实现了MethodRule而不是TestRule 。 这篇文章基于最新的JUnit版本,其中MethodRule被标记为@DeprecatedTestRule代替MethodRule 。 但是,鉴于此职位的知识,仍然应该很容易理解实现↩


参考:来自JCG合作伙伴 Frank Appel的JUnit规则 ,位于Code Affine博客上。

翻译自: https://www.javacodegeeks.com/2012/11/junit-rules.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/370676.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微pe工具箱是微软的吗_微PE工具箱V2.0更新10内核

本帖最后由 韦小宝2 于 2017-3-22 21:26 编辑微PE工具箱V2.0发布更新了,链接:http://pan.baidu.com/s/1c9whpO 转载自无忧论坛 07年,第一个XP内核通用PE工具箱发布。17年,第一个WIN10内核的微PE工具箱就此诞生。64位纯内核&#x…

jq实现轮播图

之前设计了一个校团委网站,里面有一个轮播图效果,上网后查看了许多方法,觉得下面这个方法最为适用,记录下来 js代码: $(document).ready(function () {//无缝切换轮播var i 0;//索引var clone $(".banner .imgL…

关于图片预加载的思考

引子&#xff1a; 很多时候&#xff0c;我们在写html页面的时候&#xff0c;当需要在页面中加入图片时&#xff0c;我们很自然地把图片直接用<img>标签放在了<body>里面&#xff0c;这本来是没有多大问题的。 但是当图片数量很多的时候&#xff0c;问题就来了。H…

oracle安装中桌面模式与服务器模式的去别

桌面模式只能本机使用。 服务器模式可以在网络中使用&#xff0c;也就是网络中的其他服务器可以使用。 所以安装时&#xff0c;如果是生产环境肯定是服务器模式。一般也都是服务器模式。 转载于:https://www.cnblogs.com/zhjx0521/p/7803691.html

python不能创建字典的是_用Python创建带有重复键的字典

用Python创建带有重复键的字典 我有以下列表&#xff0c;其中包含重复的具有不同值的汽车注册号。 我想将其转换为字典&#xff0c;该字典接受汽车登记号的多个键。 到目前为止&#xff0c;当我尝试将列表转换为字典时&#xff0c;它消除了键之一。 如何制作具有重复键的字典&a…

python中int是什么的缩写_python中int是什么类型

python中的基本数据类型1:虽然python中的变量不需要声明&#xff0c;但使用时必须赋值整形变量浮点型变量字符型2:可以一个给多个变量赋值&#xff0c;也可以多个给多个变量赋值3:python3中有6个标准数据类型Number(数字)*True1*False0*数值的除法(/)总是返回一个浮点数&#x…

redis cli命令

redis安装后&#xff0c;在src和/usr/local/bin下有几个以redis开头的可执行文件&#xff0c;称为redis shell&#xff0c;这些可执行文件可做很多事情。 可执行文件作用redis-server 启动redisredis-cliredis命令行工具redis-benchmark基准测试工具redis-check-aofAOF持久化文…

高级ZK:异步UI更新和后台处理–第2部分

介绍 在第1部分中&#xff0c;我展示了如何在ZK应用程序中使用服务器推送和线程来执行后台任务。 但是&#xff0c;这个简单的示例具有一个重大缺陷&#xff0c;这使其对于实际应用程序而言是一种不好的方法&#xff1a;它为每个后台任务启动了一个新线程。 JDK5引入了Execut…

css清除浮动的原理

最近学习css发现了高度塌陷时候要清除浮动,为了理解清楚浮动原理,网上找了不少资料,发现都写的不是很清楚,而且都是一模一样的内容,我在里分享一下我对清楚浮动原理的理解, 如果你已经很了解什么是浮动和浮动的效果你可以直接跳转到三.如何清除浮动(重点)阅读 一.什么是浮动首…

SpringBoot03 项目热部署

1 问题 在编写springBoot项目时&#xff0c;经常需要修改代码&#xff1b;但是每次修改代码后都需重新启动&#xff0c;修改的代码才会生效 2 这么实现IDEA能够像Eclipse那样保存过后就可以自动进行刷新呢 将springBoot项目进行热部署即可 3 如何实现SpringBoot项目的热部署01 …

STM32实现流水灯

led.c #include"led.h"void Led_Init(void) {GPIO_InitTypeDef GPIO_VALUE; //???RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//???GPIO_VALUE.GPIO_ModeGPIO_Mode_Out_PP;//???? ????GPIO_VALUE.GPIO_PinGPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_…

jacob 报错 Can't co-create object

问题&#xff1a;开始时一切正常&#xff0c;后来什么都没该&#xff0c;出现Cant co-create object报错&#xff0c;即是创建不了ActiveXComponent wdnew ActiveXComponent("Word.Application"); 偶尔发现任务管理器中word进程居然达到10个&#xff0c;而我没有打开…

map分组后取前10个_map根据属性排序、取出map前n个

/*** map根据value排序* flag 1 正序* flag 0 倒序** param map* param flag* return*/public static > LinkedHashMap sortByValue(Map map, int flag) {LinkedHashMap sortMap new LinkedHashMap<>();if (flag 1) {map.entrySet().stream().sorted(Comparator.c…

wxpython可视化_使用wxPython的绘图模块wxPyPlot进行数据可视化

[Python进阶(四十)-数据可视化の使用matplotlib进行绘图前言  matplotlib是基于Python语言的开源项目&#xff0c;旨在为Python提供一个数据绘图包。我将在这篇文章中介绍matplotlib A #-*- coding: utf-8 -*- ############################################################…

在Java EE 6中将Bean验证与JAX-RS集成

JavaBeans验证&#xff08;Bean验证&#xff09;是一种新的验证模型&#xff0c;可作为Java EE 6平台的一部分使用。 约束条件支持Bean验证模型&#xff0c;该约束以注释的形式出现在JavaBeans组件&#xff08;例如托管Bean&#xff09;的字段&#xff0c;方法或类上。 javax.…

如何让浮动的元素换行??css

当你想要做成这种布局效果的时候 紫色框里面的内容那样 它是一个列表 li元素是块级元素 默认大小是父元素ul的宽 并且换行 如果li没有背景的话那就不用管了 可是问题来了它不但有背景 而且是根据文字自适应的宽高 这就是inline-block类型的功能了 那么想让li是inline-bl…

Python学习之类和实例

面向对象最重要的概念就是类&#xff08;Class&#xff09;和实例&#xff08;Instance&#xff09;&#xff0c;必须牢记类是抽象的模板&#xff0c;比如Student类&#xff0c;而实例是根据类创建出来的一个个具体的“对象”&#xff0c;每个对象都拥有相同的方法&#xff0c;…

解决sublime里面的vue高亮的问题

下载插件文件&#xff1a;https://github.com/vuejs/vue-syntax-highlight 直接在官网下载放在安装时候的packages目录下&#xff08;sublime text3\Sublime Text3\Data\Packages&#xff09; 在Packages文件夹下新建一个vue的文件&#xff0c;把第一步下载的文件复制进去 subl…

python矩形填充颜色_在Python中找到所有用0填充的矩形

假设我们有一个二进制2D矩阵&#xff0c;现在我们必须找到所有用0填充的矩形的起点和终点。我们必须牢记&#xff0c;矩形是分开的&#xff0c;彼此之间不接触&#xff0c;但是它们可以接触阵列边界。仅包含单个元素的矩形也是可能的。所以&#xff0c;如果输入像-101110111011…

python concat_python中merge、concat用法

转载&#xff1a;https://blog.csdn.net/ly_ysys629/article/details/73849543 参考&#xff1a;https://blog.csdn.net/stevenkwong/article/details/52540605 数据规整化&#xff1a;合并、清理、过滤 pandas和python标准库提供了一整套高级、灵活的、高效的核心函数和算法将…