我们已经对Java最普遍的测试框架的下一个版本了解很多。 现在让我们看一下JUnit 5扩展模型,该模型将允许库和框架将自己的实现添加到JUnit中。

总览

  • 设定
  • 基本
  • 建筑
  • 扩展模型
  • 条件
  • 注射

在新兴的《 JUnit 5用户指南》中可以找到您将在此处阅读的更多内容以及更多内容。 请注意,它基于Alpha版本,因此可能会发生变化。

确实,我们鼓励我们提出问题或提出请求,以便JUnit 5可以进一步改进。 请利用这个机会! 这是我们帮助JUnit帮助我们的机会,因此,如果您能在这里看到一些改善,请确保将其上游 。

如有必要,此帖子将得到更新。 我在这里显示的代码示例可以在GitHub上找到 。

JUnit 4扩展模型

首先让我们看一下JUnit 4是如何解决该问题的。 它具有两个部分竞争的扩展机制:运行程序和规则。

跑步者

测试运行者管理测试的生命周期:实例化,调用设置和拆卸方法,运行测试,处理异常,发送通知等。而JUnit 4提供了实现所有这些功能的实现。

在4.0中,只有一种扩展JUnit的方法:创建一个新的运行器并使用@RunWith(MyRunner.class)注释测试类,以便JUnit使用它而不是其自己的实现。

该机制非常繁重,并且不方便扩展。 而且它有一个非常严格的限制:每个测试班级只能有一位跑步者,这使得他们无法组成。 因此,无法同时利用Mockito和Spring跑步者的功能。

规则

为了克服这些限制,JUnit 4.7引入了rules ,它们是测试类的带注释字段。 JUnit 4将测试方法(和其他操作)包装到一条语句中,并将其传递给规则。 然后,他们可以在执行语句之前和之后执行一些代码。 此外,测试方法通常在执行期间在规则实例上调用方法。

一个示例是临时文件夹规则 :

public static class HasTempFolder {@Rulepublic TemporaryFolder folder= new TemporaryFolder();@Testpublic void testUsingTempFolder() throws IOException {File createdFile= folder.newFile("myfile.txt");File createdFolder= folder.newFolder("subfolder");// ...}
}

由于使用@Rule批注,JUnit调用带有包装方法testUsingTempFolder的语句的文件夹 。 编写此特定规则是为了使文件夹创建一个临时文件夹,执行测试,然后再删除该文件夹。 然后,测试本身可以在临时文件夹中创建文件和文件夹。

其他规则可能会在Swing的事件分发线程中运行测试 ,建立和删除数据库,或者如果测试运行时间过长,则让测试超时 。

规则是一个很大的改进,但通常仅限于在测试运行之前和之后执行一些代码。 他们无法帮助无法在该框架内实现的扩展。

事态

JUnit有两种相互竞争的扩展机制,每种都有其自身的局限性。

因此,自JUnit 4.7起就有两种竞争的扩展机制,每种机制都有其自身的局限性,但也有很多重叠之处。 这使得干净扩展很困难。 此外,编写不同的扩展可能会出现问题,并且通常无法实现开发人员希望的那样。

由Tony Walmsley在CC-BY 2.0下发布

JUnit 5扩展模型

JUnit Lambda项目具有几个核心原则 ,其中之一是“优先于功能而不是扩展点”。 从字面上看,这转化为新版本的整体机制–这不仅是扩展JUnit 5的唯一机制,也是最重要的机制。

延伸点

JUnit 5扩展可以声明对测试生命周期的某些特定时刻感兴趣。 当JUnit 5引擎处理测试时,它将逐步通过这些步骤并调用每个已注册的扩展。 从外观上看,这些是扩展点:

  • 测试实例后处理
  • 之前回调
  • 有条件的测试执行
  • 每次回调之前
  • 参数解析
  • 异常处理
  • AfterEach回调
  • 毕竟回调

(不必担心它们是否每个都还不清楚。我们稍后将介绍其中的一些。)

每个扩展点对应一个接口。 他们的方法采用的参数可以捕获测试生命周期中特定点的上下文,例如测试实例和方法,测试名称,参数,注释等。

扩展可以实现任意数量的那些接口,并且将由引擎使用相应的参数进行调用。 然后,它可以执行实现其功能所需的任何操作。 要考虑的一个细节:引擎在实例化扩展时以及实例保持存在的时间方面不做任何保证,因此它们必须是无状态的。 他们需要维护的任何状态都必须写入JUnit并从中加载。

创建扩展后,剩下要做的就是告诉JUnit。 这是那么容易,因为添加@ExtendWith(MyExtension。 类 ),需要延长测试类或方法。

实际上,存在一个稍微不那么冗长和更多显示的选项。 但是为此,我们首先必须看看JUnit扩展模型的另一个Struts。

自定义注释

JUnit 5 API由注释驱动,并且引擎在检查它们是否存在时会做一些额外的工作:它不仅在类,方法和参数上查找注释,还在其他注释上查找。 并且它将发现的所有内容都视为立即存在于检查的元素上。 注释可以通过所谓的meta-annotations进行注释 ,很酷的是,所有JUnit注释都是完全meta的。

这样就可以轻松地创建和编写在JUnit 5中完全可用的注释:

/*** We define a custom annotation that:* - stands in for '@Test' so that the method gets executed* - has the tag "integration" so we can filter by that,*   e.g. when running tests from the command line*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Test
@Tag("integration")
public @interface IntegrationTest { }

然后我们可以像这样使用它:

@IntegrationTest
void runsWithCustomAnnotation() {// this gets executed// even though `@IntegrationTest` is not defined by JUnit
}

或者我们可以为扩展创建更简洁的注释:

@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(ExternalDatabaseExtension.class)
public @interface Database { }

现在我们可以使用@Database代替@ExtendWith(ExternalDatabaseExtension。 类 )。 并且由于我们添加了ElementType 。 ANNOTATION_TYPE到允许的目标列表中,它也是一个元注释,我们或其他人可以对其进行进一步的组合。

假设我们要对某些测试的运行时间进行基准测试。 首先,我们创建要使用的注释:

@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(BenchmarkCondition.class)
public @interface Benchmark { }

它已经指向BenchmarkCondition ,我们将在接下来实现。 这是我们的计划:

  • 衡量整个测试类的运行时间,存储执行任何测试之前的时间
  • 衡量各个测试方法的运行时间,存储每次测试之前的时间
  • 执行测试方法后,检索测试的启动时间,计算并打印结果运行时
  • 执行完所有测试后,检索类的启动时间,计算并打印结果运行时
  • 仅当用@Benchmark注释类或方法时,才执行任何此操作

最后一点可能不是立即显而易见的。 为什么扩展未处理未使用@Benchmark注释的方法? 这源于以下事实:如果将扩展应用于类,它将自动应用于其中的所有方法。 因此,如果我们的要求表明我们可能希望对类进行基准测试,但不一定要对所有单个方法进行基准测试,则需要排除它们。 我们通过检查它们是否被单独注释来做到这一点。

碰巧的是,前四个点直接对应于生命周期回调BeforeAllBeforeEachAfterEachAfterAll ,因此我们要做的就是实现四个对应的接口。 这些实现非常简单,它们只是按照我们上面所说的去做:

public class BenchmarkCondition implementsBeforeAllExtensionPoint, BeforeEachExtensionPoint,AfterEachExtensionPoint, AfterAllExtensionPoint {private static final Namespace NAMESPACE =Namespace.of("BenchmarkCondition");@Overridepublic void beforeAll(ContainerExtensionContext context) {if (!shouldBeBenchmarked(context))return;writeCurrentTime(context, LaunchTimeKey.CLASS);}@Overridepublic void beforeEach(TestExtensionContext context) {if (!shouldBeBenchmarked(context))return;writeCurrentTime(context, LaunchTimeKey.TEST);}@Overridepublic void afterEach(TestExtensionContext context) {if (!shouldBeBenchmarked(context))return;long launchTime = loadLaunchTime(context, LaunchTimeKey.TEST);long runtime = currentTimeMillis() - launchTime;print("Test", context.getDisplayName(), runtime);}@Overridepublic void afterAll(ContainerExtensionContext context) {if (!shouldBeBenchmarked(context))return;long launchTime = loadLaunchTime(context, LaunchTimeKey.CLASS);long runtime = currentTimeMillis() - launchTime;print("Test container", context.getDisplayName(), runtime);}private static boolean shouldBeBenchmarked(ExtensionContext context) {return context.getElement().isAnnotationPresent(Benchmark.class);}private static void writeCurrentTime(ExtensionContext context, LaunchTimeKey key) {context.getStore(NAMESPACE).put(key, currentTimeMillis());}private static long loadLaunchTime(ExtensionContext context, LaunchTimeKey key) {return (Long) context.getStore(NAMESPACE).remove(key);}private static void print(String unit, String displayName, long runtime) {System.out.printf("%s '%s' took %d ms.%n", unit, displayName, runtime);}private enum LaunchTimeKey {CLASS, TEST}
}

有趣的细节是shouldBeBenchmarked ,它使用JUnit的API毫不费力地确定当前元素是否使用@Benchmark进行 (元注释),以及writeCurrentTime / loadLaunchTime ,后者使用存储来写入和读取启动时间。

  • 您可以在GitHub上找到代码 。

接下来的文章将讨论条件测试执行和参数注入,并显示如何使用相应扩展点的示例。 如果您迫不及待,请查看这篇文章 ,其中展示了如何将两个JUnit 4规则(条件禁用和临时文件夹)移植到JUnit 5。

摘要

我们已经看到,JUnit 4的运行者和规则对于创建干净,强大且可组合的扩展并不是理想的选择。 JUnit 5旨在通过更通用的扩展点概念来克服它们的局限性。 它们允许扩展程序指定要在测试生命周期中的哪些时间点进行干预。 我们还研究了元注释如何使自定义注释的创建变得容易。

你怎么看?

翻译自: https://www.javacodegeeks.com/2016/04/junit-5-extension-model.html

JUnit 5 –扩展模型相关推荐

  1. JUnit 5扩展模型的生命周期

    JUnit5最终版本即将来临 (当前是M4),我已经开始研究如何编写扩展. 在JUnit5中 ,您没有使用Runners , Rules , ClassRules等,而是只有一个Extension A ...

  2. 扩展 junit 框架_JUnit 5 –扩展模型

    扩展 junit 框架 我们已经对Java最普遍的测试框架的下一个版本了解很多. 现在,让我们看一下JUnit 5扩展模型,该模型将允许库和框架将自己的实现添加到JUnit中. 总览 建立 基本 建筑 ...

  3. BERT-QE:用于文档Rerank的上下文化查询扩展模型

    BERT-QE 论文名称:EMNLP2020 | BERT-QE: Contextualized Query Expansion for Document Re-ranking arxiv地址:htt ...

  4. 中台背景下的多端自适应的业务扩展模型架构实践

    前言 随着数字化变革的持续深入和中台战略的落地,越来来越多的最佳实践涌现出来,这里我不在赘述什么是数字化转型和什么是中台,这里我分享一下我们在中台建设中的一些顶层思考和实践.在中台规划之前中我一直在思 ...

  5. 扩展 junit 框架_JUnit 5扩展模型的生命周期

    扩展 junit 框架 JUnit5最终版本即将来临 (当前是M4),我已经开始尝试如何编写扩展了. 在JUnit5中 ,您没有使用Runners , Rules , ClassRules等,而是只有 ...

  6. [转]c# 中间件 的扩展模型(.net webapi/.net Core 的 MiddleWare 处理模型)

    在学习 asp.net WebApi 或者asp.net Core 的时候,它们管道的处理模型跟 asp.net MVC/WebForm 的管道模型是不一样的. asp.net WebApi 或者as ...

  7. 基于AKF可扩展模型的微服务拆分方式

    前言 当我们需要分布式系统提供更强的性能时,该怎样扩展系统呢?什么时候该加机器?什么时候该重构代码?扩容时,究竟该选择哈希算法还是最小连接数算法,才能有效提升性能? 在面对 Scalability 可 ...

  8. 用ObjectProxy扩展模型对象

    参考http://www.riaspace.com/2010/11/extending-model-objects-with-objectproxy-class/

  9. JUnit 5 简介

    转自:https://www.ibm.com/developerworks/cn/java/j-introducing-junit5-part1-jupiter-api/index.html http ...

最新文章

  1. 成功解决未授予用户在此计算机上的请求登录类型图文教程
  2. Spring注释详解
  3. Condition类必须配合Mutex使用,why?
  4. [导入]心平气和,千佳骈集;意粗性躁,一事无成
  5. 文本内容之间的关键词提取和相似度计算
  6. “模板法”学习类pinterest瀑布流的前端实现
  7. 2020微信生态全景运营白皮书:10大热门场景、5大案例剖析.pdf(附下载链接)
  8. 【实习之T100开发】T100 单档程序开发(2)添加功能
  9. 基于堆叠卷积长短期神经网络【CNNLSTM】模型的时序数据预测分析
  10. 数字信号处理技术(二)变分模态分解(VMD)-Python代码
  11. mmap库:Python内存映射文件操作
  12. ggplot做双曲线阈值火山图
  13. 黑马程序员—黑马的学习环境没有亲身经历的人是很难体会的!!!
  14. python+django+mysql电影院选座订票系统毕业设计毕设开题报告
  15. pngimg 可以商用吗_设计师你还在担心素材版权吗?大量免费可商用素材在这里...
  16. 大疆2019校招提前批机器学习算法工程师在线笔试题目回忆版
  17. 计算机制造属于轻工业吗,哪些行业属于轻工业?
  18. 2023哈尔滨工业大学计算机考研信息汇总
  19. 从千牛产品策略看电商客服接待场景
  20. 计算机网络实验一层二叉树,2016考研计算机冲刺考点梳理:二叉树算法(1)

热门文章

  1. 软件开发的微信公众号分享
  2. Java命令学习系列(三)——Jmap
  3. 抖音上非常火的旋转图快速部署
  4. 下午带着几个同学打了两节课的牌~
  5. Ajax基本案例详解之$.post的实现
  6. React中的this指向问题
  7. 2015蓝桥杯省赛---java---C---1(隔行变色)
  8. php curl post 超时设置,在PHP中设置curl的超时参数(timeout)
  9. controller如何保证当前只有一个线程执行_聊聊Spring线程安全,读完之后,大部分程序员收藏了......
  10. ajax调用后台java类_ajax调用java后台方法是什么