系列入口:html
Junit4 架构设计系列(1): Request,ClassRequest 和 RunnerBuilder设计模式
前文中,咱们基本理清了Junit4执行Case大致上的Flow:
Request -> ClassRequest.getRunner() -> AllDefaultPossibilitiesBuilder.safeRunnerForClass() -> runner.run()架构
而且介绍了类Request,ClassRequest,和RunnerBuilder,剩下runner.run()没讲,那本文就从这提及。ide
run()方法是抽象类Runner定义的一个方法,目的就是执行Case。各个Runner的子类都要实现这个方法。ui
/** * Run the tests for this runner. * * @param notifier will be notified of events while tests are being run--tests being * started, finishing, and failing */ public abstract void run(RunNotifier notifier);
从前文知道,默认负责执行Junit4风格case的Runner是BlockJUnit4ClassRunner
, 可是BlockJUnit4ClassRunner
并非直接继承与Runner类,而是中间多了一层ParentRunner<T>
, 以下图:
this
ParentRunner
类负责filter 和 sort Test Class, 处理 @BeforeClass and @AfterClass 方法, 和各类 ClassRules, 而且按顺序执行Test Class。lua
那咱们来看看ParentRunner
是如何执行Junit4风格的Test Class的,具体实现以下:架构设计
@Override public void run(final RunNotifier notifier) { EachTestNotifier testNotifier = new EachTestNotifier(notifier, getDescription()); try { Statement statement = classBlock(notifier); statement.evaluate(); } catch (AssumptionViolatedException e) { testNotifier.addFailedAssumption(e); } catch (StoppedByUserException e) { throw e; } catch (Throwable e) { testNotifier.addFailure(e); } }
第一行是实例化一个EachTestNotifier,主要为了记录执行过程的,这里暂且不作详细解释。
很明显,Try里的逻辑才是真正的执行步骤。逻辑也很清晰,就是获得Statement,而后调用evaluate()方法。设计
继续跟进方法classBlock
,咱们就会看到下面的逻辑:code
protected Statement classBlock(final RunNotifier notifier) { Statement statement = childrenInvoker(notifier); if (!areAllChildrenIgnored()) { statement = withBeforeClasses(statement); statement = withAfterClasses(statement); statement = withClassRules(statement); } return statement; }
这个逻辑是用于组合咱们指望的Statement,不难看出,Runner.run()方法主要涉及下面几个执行逻辑:
当全部的statement
包装好后,调用statement.evaluate()
就能够按要求,按顺序的执行咱们但愿的结果了。
看到这种嵌套输入与输出的写法,会不会有中恍然大悟的感受?!这不就是装饰者模式的经典适用场景嘛。
要注意的是,这里处理的都是Class,而对于Method级,实际上也有相似装饰者模式的适用场景, 咱们从上面childInvoker跟进去,最终会发现,真正执行Test Method的是BlockJunit4ClassRunner
类,首先它实现了ParentRunner
的抽象方法runChild
:
// // Implementation of ParentRunner // @Override protected void runChild(final FrameworkMethod method, RunNotifier notifier) { Description description = describeChild(method); if (isIgnored(method)) { notifier.fireTestIgnored(description); } else { Statement statement; try { statement = methodBlock(method); } catch (Throwable ex) { statement = new Fail(ex); } runLeaf(statement, description, notifier); } }
而后在期方法块中methodBlock
组合statement:
protected Statement methodBlock(final FrameworkMethod method) { Object test; try { test = new ReflectiveCallable() { @Override protected Object runReflectiveCall() throws Throwable { return createTest(method); } }.run(); } catch (Throwable e) { return new Fail(e); } Statement statement = methodInvoker(method, test); statement = possiblyExpectingExceptions(method, test, statement); statement = withPotentialTimeout(method, test, statement); statement = withBefores(method, test, statement); statement = withAfters(method, test, statement); statement = withRules(method, test, statement); return statement; }
跟ClassBlock殊途同归。
Statement在Junit4中是很是重要的一块,彻底能够大书特书,如图:
在JUnit4中,一切动做均可以用Statement来表示,从上图包的分配方式咱们能够看到,Junit4不但预约义了一些必须使用或者使用频率高的动做,如
还定义了RunRules,可以让咱们Reuse或者是从新定义本身的Rule.可谓方便至极.
Decorator(装饰者)模式动态地将责任添加到对象上。在扩展功能方面,装饰者模式提供了比继承更有弹性的替代方案。
这是我实现的标准装饰者模式的类图:
而装饰者模式特色就是:
高亮的第三点很关键,咱们知道Junit4之因此能让 @BeforeClass 和 @AfterClass 等注解,按要求或前或后的执行,就是利用了这一点。
后续计划