博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【JUnit4.10源码分析】5 Statement
阅读量:5754 次
发布时间:2019-06-18

本文共 4836 字,大约阅读时间需要 16 分钟。

假设要评选JUnit中最最重要的类型。或者说核心,无疑是org.junit.runners.model.Statement。Runner等类型看起来热闹而已。

package org.junit.runners.model;/** * Represents one or more actions to be taken at runtime in the course * of running a JUnit test suite. */public abstract class Statement {	/**	 * Run the action, throwing a {@code Throwable} if anything goes wrong.	 */	public abstract void evaluate() throws Throwable;}
Statement是
命令模式中的Command、装饰模式中的Component
。它是
Rule
发挥作用的关键。

写完之后,yqj2065就对JUnit的源码的研读缺乏激情鸟。JUnit4.10的源码在此BlockJUnit4ClassRunner没有明显的变化。

读完最精致的设计。其它还有什么好玩的呢?可能就是并行。可是并行是一种Java技术,和反射、注解、泛型一样的技术问题。不是精致的设计。准备花点时间好好写点Statement的东西补充本文。先挖坑。 先凑活着看。

命令模式的Command角色

抽象类Statement声明操作evaluate()的接口,而由其子类——详细命令或复合命令负责绑定命令的Recelver/接收者或命令的运行者。

Statement/语句是对执行JUnit測试组过程中的一个或多个动作的封装。假设说Runner.run()表示执行JUnit測试组的整个过程,则Statement表示当中或大或小的步骤。针对方法的标注如@Test 、@Before、@After、@BeforeClass、@AfterClass和各种測试场景。Statement的子类封装一个或多个动作。

最基础的详细命令有Fail和InvokeMethod。

Fail表示JUnit測试过程中遇到了问题而失败,因而其evaluate()简单地抛出一个异常。源码例如以下:

package org.junit.internal.runners.statements;import org.junit.runners.model.Statement;public class Fail extends Statement {	private final Throwable fError;	public Fail(Throwable e) {		fError= e;	}	@Override	public void evaluate() throws Throwable {		throw fError;	}}

InvokeMethod表示执行一个@Test方法的命令,这是JUnit測试的最小单元。

package org.junit.internal.runners.statements;import org.junit.runners.model.FrameworkMethod;import org.junit.runners.model.Statement;public class InvokeMethod extends Statement {	private final FrameworkMethod fTestMethod;	private Object fTarget;		public InvokeMethod(FrameworkMethod testMethod, Object target) {		fTestMethod= testMethod;		fTarget= target;	}		@Override	public void evaluate() throws Throwable {		fTestMethod.invokeExplosively(fTarget);	}}
InvokeMethod提供
的方式。获得測试单元类的对象target和FrameworkMethod。命令的运行者为FrameworkMethod对象,參数是由外界注入的Object target。

这两个样例。说明了命令模式中选择命令的运行者的极大自由。

其它的子类,属于复合命令

BlockJUnit4ClassRunner实际上是命令模式中的Client。直接调用详细的命令。依照所言。将BlockJUnit4ClassRunner相关代码放在MethodBlock中后,BlockJUnit4ClassRunner中仅仅须要把 methodBlock(method).evaluate();

改动为 new MethodBlock(method,test).evaluate();

抽象类Statement声明操作evaluate()的接口,它作为一个,上层模块能够定义各种Statement的子类。提供evaluate()的方法体。

而这一主要的技术与Rule结合。成为JUnit一个很重要的手段——能够说它是一个通用型的复合命令的构造方式。全然能够代替Statement的一些复合命令的子类如ExpectException等。

复合命令子类如ExpectException由JUnit框架的设计者提供,而使用Rule,则将复合命令子类的构造任务交给測试程序猿。所以,一般的常常使用的复合命令,还是应该作为默认实如今框架中存在

装饰模式中的Component角色

复合命令是对基本命令的拓展装饰模式的目的就是给一个对象增添一些其它的功能。简单而典型的ExpectException和FailOnTimeout,针对@Test注解中的參数。比如@Test(expected=IndexOutOfBoundsException.class)或@Test(timeout=100)。以ExpectException为例(源码中的Ststement fNext,我改成了base

package org.junit.internal.runners.statements;import org.junit.internal.AssumptionViolatedException;//意料之中的异常import org.junit.runners.model.Statement;public class ExpectException extends Statement {	private Statement base;	private final Class
fExpected; public ExpectException(Statement base, Class
expected) { this.base= base; fExpected= expected; } @Override public void evaluate() throws Exception { boolean complete = false; try { base.evaluate(); complete = true; } catch (AssumptionViolatedException e) { throw e; } catch (Throwable e) { if (!fExpected.isAssignableFrom(e.getClass())) { String message= "Unexpected exception, expected<" + fExpected.getName() + "> but was<" + e.getClass().getName() + ">"; throw new Exception(message, e); } } if (complete) throw new AssertionError("Expected exception: " + fExpected.getName()); }}
ExpectException依赖注入Statement对象——通常为@Test注解的方法的Statement。和预期的异常expected。

ExpectException在base的基础上增添了对预期的异常的处理。

base.evaluate(),假设抛出了意料之中的异常,转手抛出。假设不是意料之中的异常,说明这是一个"Unexpected exception,……";假设顺利运行没有异常。则抛出断言错误——我预期的异常在哪里?

在BlockJUnit4ClassRunner中使用代码对@Test(expected=xxx)进行的处理:

package org.junit.runners;public class MethodBlock extends Statement{//从BlockJUnit4ClassRunner中提取出来        @Deprecated    protected Statement possiblyExpectingExceptions(FrameworkMethod method,            Object test, Statement next) {        Test annotation= method.getAnnotation(Test.class);        return expectsException(annotation) ?

new ExpectException(next, getExpectedException(annotation)) : next; } private Class<? extends Throwable> getExpectedException(Test annotation) { if (annotation == null || annotation.expected() == None.class) return null; else return annotation.expected(); } private boolean expectsException(Test annotation) { return getExpectedException(annotation) != null; } }

因为使用了反射机制,装饰对象的创建与常见的方式不同,须要代码处理:

new ExpectException(next, getExpectedException(annotation)

注意。假设@Test没有指定(expected=xxx),possiblyExpectingExceptions()返回一个主要的Statement。

因为使用了反射机制,装饰模式中用户类BlockJUnit4ClassRunner须要某个Builder(在JUnit中不过一个方法)创建装饰对象ExpectException。

而这就是TestRule的作用,一个工厂方法模式中的Creator角色。

本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5177847.html,如需转载请自行联系原作者

你可能感兴趣的文章
sap关于价值串的说法(转载)
查看>>
采购申请转采购订单错误:在语言EN中没有维护短文本(请重维护物料460300080)
查看>>
Migration to S/4HANA
查看>>
SAP WM LPK1 不能把 cross-material control cycles定义成release order parts
查看>>
HTML5 & CSS3初学者指南(3) – HTML5新特性
查看>>
sed 对目录进行操作
查看>>
表格基础操作
查看>>
求空间一点到另外一点(如原点)的距离
查看>>
gitolite push fail solutions
查看>>
WIFI电源管理
查看>>
HDU4786:Fibonacci Tree(并查集)
查看>>
移动端适配(1)——viewport设置与初始化css
查看>>
阿里云PHP Redis代码示例
查看>>
php生成随机数
查看>>
2017-02-20
查看>>
win7与win7之间无法访问共享文件的问题解决(转)
查看>>
PS是LINUX下最常用的也是非常强大的进程查看命令
查看>>
插入排序
查看>>
内存管理3 - Win32汇编语言056
查看>>
一个简单的购物类网站
查看>>