第二次读junit源码,撸了个流程图,哎也算能看出点门道了,之前脑子都是晕的
总体来说,Junit单元测试的入口在JunitCore里面,通过Core调用run(Runner runner)方法走到ParentRunner(实际上一般是其继承类BlockJUnit4ClassRunner),整个流程我觉得最核心的就是Statement的传递,相当于责任链模式,比较重要的两个方法呢,就是classBlock和methodBlock两个方法。
执行的顺序是先调用classBlock,在classBlock里面再通过childrenInvoker来调用methodBlock
@Override
public void run(final RunNotifier notifier) {
EachTestNotifier testNotifier = new EachTestNotifier(notifier,
getDescription());
testNotifier.fireTestSuiteStarted();
try {
Statement statement = classBlock(notifier);
statement.evaluate();
} catch (AssumptionViolatedException e) {
testNotifier.addFailedAssumption(e);
} catch (StoppedByUserException e) {
throw e;
} catch (Throwable e) {
testNotifier.addFailure(e);
} finally {
testNotifier.fireTestSuiteFinished();
}
}
所以我们首先看classBlock
protected Statement classBlock(final RunNotifier notifier) {
Statement statement = childrenInvoker(notifier);
if (!areAllChildrenIgnored()) {
statement = withBeforeClasses(statement);
statement = withAfterClasses(statement);
statement = withClassRules(statement);
statement = withInterruptIsolation(statement);
}
return statement;
}
从上图的逻辑我们可以推断出,@BerforeClass在@Before前面面执行,因为withBeforeClass()方法在methodBlock后面,而越后面的statement越先被回调到,所以先执行@BeforeClass相关的代码。childrenInvoker暂时不管,先看后面的withBeforeClass,可以看到,如果要测试的类有BeforeClass注解,那么会返回一个RunBefores
protected Statement withBeforeClasses(Statement statement) {
List<FrameworkMethod> befores = testClass
.getAnnotatedMethods(BeforeClass.class);
return befores.isEmpty() ? statement :
new RunBefores(statement, befores, null);
}
再看RunBefores的代码:
public RunBefores(Statement next, List<FrameworkMethod> befores, Object target) {
this.next = next;
this.befores = befores;
this.target = target;
}
@Override
public void evaluate() throws Throwable {
for (FrameworkMethod before : befores) {
invokeMethod(before);
}
next.evaluate();
}
这个就相当于生成一个statement链表,再依次执行statement的evaluate方法,其他的withAfterClasses,withClassRules也是类似,withInterruptIsolation这个主要是用来处理中断的,但是为啥要处理中断,我也不知道,,,
然后再回到classBlock的childrenInvoker方法:
protected Statement childrenInvoker(final RunNotifier notifier) {
return new Statement() {
@Override
public void evaluate() {
runChildren(notifier);
}
};
}
再点进runChildren方法:
private void runChildren(final RunNotifier notifier) {
final RunnerScheduler currentScheduler = scheduler;
try {
for (final T each : getFilteredChildren()) {
currentScheduler.schedule(new Runnable() {
public void run() {
ParentRunner.this.runChild(each, notifier);
}
});
}
} finally {
currentScheduler.finished();
}
}
点进runChild:
@Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
Description description = describeChild(method);
if (isIgnored(method)) {
notifier.fireTestIgnored(description);
} else {
Statement statement = new Statement() {
@Override
public void evaluate() throws Throwable {
methodBlock(method).evaluate();
}
};
runLeaf(statement, description, notifier);
}
}
就能看到我们的methodBlock方法了:
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);
statement = withInterruptIsolation(statement);
return statement;
}
createTest()我的理解就是通过构造器加载当前测试的类,比如当前要测试的是HelloTest,拿我们就通过createTest()创建一个HelloTest实例(newInstance)
而methodInvoke(method,test)其实是一个回调函数,这个函数在BlockJUnit4ClassRunner就是返回一个new InvokeMethod,但是在TheoryAnchor里面有个被覆写的BlockJUnit4ClassRunner类,这个覆写类其实是返回一个 methodCompletesWithParameters方法,具体细节就不说了
继续看possiblyExpectingExceptions,这个其实就是对应@Test(expected = xxException)的用法,用过的都懂,withPotentialTimeout就是@Test(timeout= xx),withBefores对应@Before,后面都差不多,不过以上这些,都没有实际调用evaluate方法,只是定义了很多关于Statement evaluate回调函数,而真正的调用其实是在runChild方法的最后一行代码,runLeaf中:
/**
* Runs a {@link Statement} that represents a leaf (aka atomic) test.
*/
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();
}
}
这里面的evaluate会触发一系列的回调函数,首先是触发withInterruptIsolation的evaluate函数,因为它是最后一个声明的,然后触发withRules,依次类推,直到最后触发methodInvoker的statment的,这个statement会调用FrameworkMethod的invokeExplosively,即通过反射的方式,正式走进@Test标注的方法,开始执行测试