了解JUnit的Runner架构

几周前,我开始创建一个小的JUnit Runner( Oleaster ),它允许您使用Jasmine方式在JUnit中编写单元测试。 我了解到,创建自定义JUnit Runners实际上非常简单。 在本文中,我想向您展示JUnit Runner在内部如何工作以及如何使用自定义Runner来修改JUnit的测试执行过程。



那么什么是JUnit Runner?

JUnit Runner是扩展JUnit抽象Runner类的类。 运行程序用于运行测试类。 可以使用@RunWith注释设置应该用于运行测试的Runner 。

@RunWith(MyTestRunner.class)
public class MyTestClass {@Testpublic void myTest() {..}
}

JUnit测试是使用JUnitCore类开始的。 可以通过从命令行运行它,也可以使用其各种run()方法之一来完成此操作(如果您按run test按钮,这就是您的IDE所做的事情)。

JUnitCore.runClasses(MyTestClass.class);

然后,JUnitCore使用反射为通过的测试类找到合适的Runner。 此处的一个步骤是在测试类上查找@RunWith批注。 如果未找到其他运行程序,则将使用默认运行程序( BlockJUnit4ClassRunner )。 将实例化Runner,并将测试类传递给Runner。 现在,实例化并运行通过的测试类是Runner的工作。

跑步者如何工作?

让我们看一下标准JUnit Runners的类层次结构:

跑步者

Runner是一个非常简单的类,实现了Describable接口,并具有两个抽象方法:

public abstract class Runner implements Describable {public abstract Description getDescription();public abstract void run(RunNotifier notifier);
}

方法getDescription()从Describable继承,并且必须返回Description 。 描述包含了各种工具以后导出和使用的信息。 例如,您的IDE可能会使用此信息来显示测试结果。 run()是一种非常通用的方法, 可以运行某些内容 (例如测试类或测试套件)。 我认为通常Runner并不是您要扩展的类(它太慷慨了)。

在ParentRunner中,事情变得更加具体。 ParentRunner是具有多个子代的Runner的抽象基类。 在这里重要的是要理解,测试是按层次结构(例如树)构造和执行的。

例如:您可能运行包含其他测试套件的测试套件。 这些测试套件可能包含多个测试类。 最后,每个测试类可以包含多个测试方法。

ParentRunner具有以下三种抽象方法:

public abstract class ParentRunner<T> extends Runner implements Filterable, Sortable {    protected abstract List<T> getChildren();protected abstract Description describeChild(T child);protected abstract void runChild(T child, RunNotifier notifier);
}

子类需要在getChildren()中返回泛型T的列表。 然后,ParentRunner要求子类为每个孩子(describeChild())创建一个Description,最后运行每个孩子(runChild())。

现在,让我们看一下两个标准的ParentRunners:BlockJUnit4ClassRunner和Suite。

如果未提供其他Runner,则使用BlockJUnit4ClassRunner为默认Runner。 因此,这是运行单个测试类时通常使用的Runner。 如果您查看BlockJUnit4ClassRunner的来源,您将看到类似以下内容:

public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {@Overrideprotected List<FrameworkMethod> getChildren() {// scan test class for methonds annotated with @Test}@Overrideprotected Description describeChild(FrameworkMethod method) {// create Description based on method name}@Overrideprotected void runChild(final FrameworkMethod method, RunNotifier notifier) {if (/* method not annotated with @Ignore */) {// run methods annotated with @Before// run test method// run methods annotated with @After}}
}

当然,这被过度简化了,但是它说明了BlockJUnit4ClassRunner的基本功能。 通用类型参数FrameworkMethod基本上是java.lang.reflect.Method的包装,提供了一些方便的方法。 在getChildren()中,扫描测试类以查找使用@Test进行反射的方法。 找到的方法包装在FrameworkMethod对象中并返回。 describeChildren()从方法名称创建一个Description,然后runChild()最终运行测试方法。 BlockJUnit4ClassRunner在内部使用了很多受保护的方法。 根据您要确切执行的操作,最好检查BlockJUnit4ClassRunner中可以覆盖的方法。 您可以在GitHub上查看BlockJUnit4ClassRunner的源代码。

Suite Runner用于创建测试套件。 套件是测试(或其他套件)的集合。 一个简单的套件定义如下所示:

@RunWith(Suite.class)
@Suite.SuiteClasses({MyJUnitTestClass1.class,MyJUnitTestClass2.class,MyOtherTestSuite.class
})
public class MyTestSuite {}

通过选择带有@RunWith批注的Suite Runner来创建测试套件。 如果查看Suite的实现,您会发现它实际上非常简单。 Suite唯一要做的就是从使用@SuiteClasses批注定义的类中创建Runner实例。 因此,getChildren()返回Runners列表,runChild()将执行委托给相应的Runner。

例子

使用提供的信息,创建您自己的JUnit Runner并不难(至少我希望如此)。 如果您正在寻找一些示例自定义Runner实现,则可以查看以下列表:

  • Fabio Strozzi创建了一个非常简单明了的GuiceJUnitRunner项目 。 它使您可以选择在JUnit测试中注入Guice组件。 来源GitHub
  • Spring的SpringJUnit4ClassRunner可帮助您测试Spring框架应用程序。 它允许您在测试类中使用依赖项注入或创建事务性测试方法。 来源GitHub
  • Mockito为自动模拟初始化提供了MockitoJUnitRunner 。 来源GitHub
  • Oleaster的 Java 8茉莉花赛跑者。 源自GitHub (无耻的自我推广)

结论

JUnit Runners具有高度可定制性,可让您选择更改以完成测试执行过程。 很酷的事情是,可以更改整个测试过程,并且仍然使用IDE,构建服务器等的所有JUnit集成点。

如果您只想进行较小的更改,那么最好查看一下BlockJUnit4Class运行程序的受保护方法。 您很有可能在正确的位置找到可重写的方法。

翻译自: https://www.javacodegeeks.com/2014/08/understanding-junits-runner-architecture.html

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

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

相关文章

C# DateTime 格式

C# DateTime 格式 DateTime dt DateTime.Now;//Label1.Text dt.ToString();//2005-11-5 13:21:25//Label2.Text dt.ToFileTime().ToString();//127756416859912816//Label3.Text dt.ToFileTimeUtc().ToString();//127756704859912816//Label4.Text dt.ToLocalTime().ToStri…

琼瑶哀悼丈夫去世

转载于:https://www.cnblogs.com/gitwow/p/10982911.html

js slice 参数为负值

示例代码 <!DOCTYPE html><html lang"zh"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><meta http-equiv"X-UA-Compatible" con…

vue 简单实用的elementUI表格封装

在写这个表格组件之前&#xff0c;要了解 slot 插槽的使用。 目录 1.子组件&#xff1a;子组件调用父组件的方法 this.$parent.方法名 2.父组件使用 2.1 父组件&#xff08;普通表格&#xff09;&#xff1a; 2.2 父组件&#xff08;表格中的某一项数据需要修改&#xff0…

Java私有,受保护,公共和默认

您是Java程序员&#xff0c;所以您知道我在说什么。 public修饰符使方法或字段可从应用程序中的任何位置访问。 那是简单的部分。 但是&#xff0c;您能告诉我protected包和私有包的区别吗&#xff1f; &#xff08;提示&#xff1a;当您不在方法或字段前面编写任何访问修饰符时…

vue vuex 大型项目demo示例

1、vuex 动态模块配置 import Vue from vueimport Vuex from vueximport store from /store;// 使用Vuex插件&#xff0c;即使插件被调用多次&#xff0c;插件也只会安装一次Vue.use(Vuex);// state存储数据的状态const state {// 数据状态name: mfg}// getters获取数据状态co…

【学习】012 垃圾回收机制算法分析

垃圾回收机制概述 Java语言中一个显著的特点就是引入了垃圾回收机制&#xff0c;使c程序员最头疼的内存管理的问题迎刃而解&#xff0c;它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制&#xff0c;Java中的对象不再有“作用域”的概念&#xff0…

js 计算对象数组中某个属性值重复出现的个数

转载于&#xff1a;前进中的蜗牛 let list [{name:"1000积分",serialNumber:6},{name:"500积分",serialNumber:7},{name:"50积分",serialNumber:8},{name:"50积分",serialNumber:8},{name:"50积分",serialNumber:8} ];//怎…

介绍JBoss BPM Suite安装程序

本周&#xff0c;我们想向您介绍JBoss BRMS和JBoss BPM Suite产品随附的一个鲜为人知的安装程序组件。 请注意&#xff0c;当前所有的演示项目都要求您下载JBoss BPM Suite可部署的eap zip产品文件和JBoss EAP 6.1.1 zip产品文件。 展望未来&#xff0c;我们将迁移所有项目&am…

小程序 报错errMsg: “hideLoading:fail:toast can‘t be found“ ?

小程序体验版上/真机上报错&#xff1a;errMsg: "hideLoading:fail:toast cant be found" &#xff1f;模拟器上却看不到&#xff0c; wx.showLoading 和 wx.showToast 同时只能显示一个&#xff1b;wx.showLoading 应与 wx.hideLoading 配对使用&#xff1b;把请求…

世界名牌大学课件下载地址

一、加州大学伯克利分校 http://webcast.berkeley.edu/courses.php 作为美国第一的公立大学&#xff0c;伯克利分校提供了许多优秀教授的播客和视频讲座&#xff0c;可以跟踪最新的讲座。想看教授布置的作业和课堂笔记&#xff0c;可以点击该教授的网页&#xff0c;通常&#…

jquery-deferred应用

我们说jquery1.5之后用的用deferred&#xff0c;那么deferred到底是个什么东西&#xff0c;看个例子var wait function(){var task function(){console.log(执行完成);}setTimeout(task, 2000); } wait(); 现在在task里面的执行完成之后进行某些特别复杂的操作&#xff0c;代…

自动装箱,拆箱和NoSuchMethodError

J2SE 5为Java编程语言引入了许多功能。 这些功能之一是自动装箱和拆箱 &#xff0c;这是我几乎每天都没有考虑过的功能。 它通常很方便&#xff08;尤其是与收藏夹一起使用时&#xff09;&#xff0c;但有时会导致一些令人讨厌的惊喜 &#xff0c;即“ 怪异 ”和“ 疯狂” 。 在…

vue 不能监测数组长度变化length的原因

由于 JavaScript 的限制&#xff0c;Vue 不能检测以下变动的数组&#xff1a; 当你利用索引直接设置一个项时&#xff0c;例如&#xff1a; vm.items[indexOfItem] newValue 当你修改数组的长度时&#xff0c;例如&#xff1a; vm.items.length newLength因为vue的响应式是通…

vue 动态显示三级路由

无需 vuex、本地存储实现动态显示三级路由。 目录 一、需求描述&#xff1a; 二、代码 2.1 路由配置 1. 我的一级菜单和二级菜单的路由配置的&#xff1a; 2. 三级菜单的路由配置&#xff1a; 3. 上面有几个变量和要注意的细节&#xff1a; 2.2 封装导航栏 2.3 封装面…

第二章 Vue快速入门-- 18 v-for中key的使用注意事项

注意:如果属性和方法还没定义直接使用的话&#xff0c;就会报 xxx is not defined 导致界面不能正常显示。我看视频教程里老师的可以直接使用&#xff0c;而且界面正常显示&#xff0c;可能是vue版本不同吗&#xff1f;还不清楚 1 <!DOCTYPE html>2 <html lang"…

口碑网发布2010吃住玩消费风向指数

当在淘宝网上买衣服、买电器、买……都变得司空见惯&#xff0c;下一步我们会在网上完成什么消费&#xff1f; 通过网购等电子商务模式的带动&#xff0c;电子商务平台对于老百姓日常消费、生活的影响逐渐深化。原本更多依靠传统手段完成的吃住玩等生活消费&#xff0c;现在也…

Java并发教程–线程安全设计

在回顾了处理并发程序时的主要风险&#xff08;如原子性或可见性 &#xff09;之后&#xff0c;我们将进行一些类设计&#xff0c;以帮助我们防止上述错误。 其中一些设计导致了线程安全对象的构造&#xff0c;从而使我们可以在线程之间安全地共享它们。 作为示例&#xff0c;我…

ES6 iterator 迭代器

iterator使用TypeScript 的描述&#xff1a; interface Iterable {[Symbol.iterator]() : Iterator,}interface Iterator {next(value?: any) : IterationResult,}interface IterationResult {value: any,done: boolean,} 一个数据结构只要具有 Symbol.iterator属性&#xff0…

vue 后端返回二进制流文件,前端如何实现下载?

目录 1. axios 请求二进制流文件导出文件 1.1 后台返回的二进制流&#xff1a; 1.2 使用&#xff1a; 1.3 需要注意以下几点&#xff1a; 2. 关于 arraybuffer 和 blob 2.1 ArrayBuffer 和 blob 2.2 区别 2.3 相互转换 3. 主要参考&#xff1a; 1. axios 请求二进制…