设为首页 加入收藏

TOP

JUnit 源码解析(三)
2018-01-30 12:42:55 】 浏览:497
Tags:JUnit 源码 解析
statement = withAfters(method, test, statement); statement = withRules(method, test, statement); return statement; }

前面的几行代码是在生成test 对象,而test对象的类型则是我们待测试的class,接下来追进methodInvoker方法:

protected Statement methodInvoker(FrameworkMethod method, Object test) {
        return new InvokeMethod(method, test);
}

可见,我们生成的Statement实例为InvokeMethod,我们看下其eva luate方法:

testMethod.invokeExplosively(target);

invokeExplosively函数做的事情就是对target对象调用testMethod方法。而前面我们说过,这个testMethod在BlockJUnit4ClassRunner中就是被@Test所标注的方法,此时,我们终于找到了@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);

我们可以看到,statement不断的在变形,而通过withBefores,withRules这些函数的名字我们可以很容易猜到,这里就是在处理@Before,@Rule等注解的地方,我们以withBefores为例:

protected Statement withBefores(FrameworkMethod method, Object target,
            Statement statement) {
        List<FrameworkMethod> befores = getTestClass().getAnnotatedMethods(
                Before.class);
        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 eva luate() throws Throwable {
       for (FrameworkMethod before : befores) {
            before.invokeExplosively(target);
       }
       next.eva luate();
}

很是明了,eva luate执行时,首先将before方法全部invoke来执行,然后才调用原始statement的eva luate方法。其余几个函数与此类似,感兴趣可以继续查看。

如此,我们就明白了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.eva luate();
        } catch (AssumptionViolatedException e) {
            eachNotifier.addFailedAssumption(e);
        } catch (Throwable e) {
            eachNotifier.addFailure(e);
        } finally {
            eachNotifier.fireTestFinished();
        }
}

非常简单,直接执行了statement的eva luate方法,需要注意的是这里的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注解的方法只能是st

首页 上一页 1 2 3 4 下一页 尾页 3/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇JUnit 源码解析 下一篇理解 Consistent Hashing

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目