JUnit源码解析(4)

发表于:2016-10-04来源:saymagic作者:saymagic点击数: 标签:junit
return befores.isEmpty() ? statement : new RunBefores(statement, befores, target); } 这个函数里首先拿到了所有被@Before标注的方法,将其封装为RunBefores,我们看下其构造函数
        return befores.isEmpty() ? statement : new RunBefores(statement,
                befores, target);
}
这个函数里首先拿到了所有被@Before标注的方法,将其封装为RunBefores,我们看下其构造函数和
 
public RunBefores(Statement next, List<FrameworkMethod> befores, Object target) {
        this.next = next;
        this.befores = befores;
        this.target = target;
}
public void evaluate() throws Throwable {
       for (FrameworkMethod before : befores) {
            before.invokeExplosively(target);
       }
       next.evaluate();
}
很是明了,evaluate执行时,首先将before方法全部invoke来执行,然后才调用原始statement的evaluate方法。其余几个函数与此类似,感兴趣可以继续查看。
 
如此,我们就明白了runLeaf方法的第一个参数Statement的由来,接下来就看下这个runLeaf方法做了什么,runLeaf在ParentRunner中有默认的实现:
 
 protected final void runLeaf(Statement statement, Description description,
            RunNotifier notifier) {
        EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description);
        eachNotifier.fireTestStarted();
        try {
            statement.evaluate();
        } catch (AssumptionViolatedException e) {
            eachNotifier.addFailedAssumption(e);
        } catch (Throwable e) {
            eachNotifier.addFailure(e);
        } finally {
            eachNotifier.fireTestFinished();
        }
}
非常简单,直接执行了statement的evaluate方法,需要注意的是这里的statement实例不一定是什么了,有可能是RunBefores,也有可能是RunAfters,这就和被测试类中的注解有关了。
 
讲到这里,还记得前面我们说过的存档A吗?我们回到存档A:
 
protected Statement classBlock(final RunNotifier notifier) {
     Statement statement = childrenInvoker(notifier);
     if (!areAllChildrenIgnored()) {
         statement = withBeforeClasses(statement);
         statement = withAfterClasses(statement);
         statement = withClassRules(statement);
     }
     return statement;
}
刚刚存档后所发生的一起,其实就是在执行Statement statement = childrenInvoker(notifier)这个代码。换句话说,childrenInvoker的作用就是将所有需要执行的测试用例用一个Statement封装起来。进而点燃这个Statement,就会触发所有的测试用例。但同样需要注意到被if语句包围的代码,我们又看到了熟悉的语句,Statement还在被不断的转换,但此时是在类的层面,withBeforeClasses函数操作的就是@BeforeClass注解了:
 
protected Statement withBeforeClasses(Statement statement) {
        List<FrameworkMethod> befores = testClass
                .getAnnotatedMethods(BeforeClass.class);
        return befores.isEmpty() ? statement :
                new RunBefores(statement, befores, null);
}
需要注意的是这回RunBefores的第三个参数为null,说明被@BeforeClass注解的方法只能是static的。
 
如上,我们分析了BlockJUnit4ClassRunner的运行流程,也就是说当测试类为一个的时候JUnit是如何工作的。前文也提到过,ParentRunner还有一个子类Suite,表示需要运行一组测试,BlockJUnit4ClassRunner的一个运行单元为FrameworkMethod,而Suite的一个运行单元为Runner,我们看其runChild方法:
 
protected void runChild(Runner runner, final RunNotifier notifier) {

原文转自:http://blog.saymagic.cn/2016/09/30/understand-Junit.html