methodsForAnnotations);
}
// ensuring fields are sorted to make sure that entries are inserted
// and read from fieldForAnnotations in a deterministic order
for (Field eachField : getSortedDeclaredFields(eachClass)) {
addToAnnotationLists(new FrameworkField(eachField), fieldsForAnnotations);
}
}
}
整个函数的作用就是扫描class中方法和变量上的注解,并将其根据注解的类型进行分类,缓存在methodsForAnnotations与fieldsForAnnotations当中。需要注意的是,JUnit对方法和变量分别封装为FrameworkMethod与FrameworkField,它们都继承自FrameworkMember,这样就为方法和变量进行了统一抽象。
看完了ParentRunner的构造函数,我们来看ParentRunner继承自Runner的run方法是如何工作的:
@Override
public void run(final RunNotifier notifier) {
EachTestNotifier testNotifier = new EachTestNotifier(notifier,
getDescription());
try {
Statement statement = classBlock(notifier);
statement.eva luate();
} catch (AssumptionViolatedException e) {
testNotifier.addFailedAssumption(e);
} catch (StoppedByUserException e) {
throw e;
} catch (Throwable e) {
testNotifier.addFailure(e);
}
}
其中比较关键的代码是classBlock函数将notifier转换为Statement:
protected Statement classBlock(final RunNotifier notifier) {
Statement statement = childrenInvoker(notifier);
if (!areAllChildrenIgnored()) {
statement = withBeforeClasses(statement);
statement = withAfterClasses(statement);
statement = withClassRules(statement);
}
return statement;
}
继续追进childrenInvoker之前,允许我现在这里先存个档,记为A,一会我们会回到classBlock这里
protected Statement childrenInvoker(final RunNotifier notifier) {
return new Statement() {
@Override
public void eva luate() {
runChildren(notifier);
}
};
}
childrenInvoker返回的是一个Statement,看它的eva luate方法,其调用的是runChildren方法,这也是ParentRunner中非常重要的一个函数:
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();
}
}
这个函数就体现了抽象的重要性,注意泛型T,它在ParentRunner的每个实现类中各不相同,在BlockJUnit4ClassRunner中T表示FrameworkMethod,具体到这个函数来讲getFilteredChildren拿到的是被@Test注解标注的FrameworkMethod,而在Suite中,T为Runner,而ParentRunner.this.runChild(each, notifier);这句的中的runChild(each, notifier)方法依旧是个抽象方法,我们先看BlockJUnit4ClassRunner中的实现:
@Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
Description description = describeChild(method);
if (isIgnored(method)) {
notifier.fireTestIgnored(description);
} else {
runLeaf(methodBlock(method), description, notifier);
}
}
isIgnored方法判断了method方法是否被@Ignore注解标识,如果是的话则直接通知notifier触发ignored事件,否则,执行runLeaf方法, runLeaf的第一个参数是Statement,所以,BlockJUnit4ClassRunner通过methodBlock方法将method转换为Statement:
protected Statement methodBlock(FrameworkMethod method) {
Object test;
try {
test = new ReflectiveCallable() {
@Override
protected Object runReflectiveCall() throws Throwable {
return createTest();
}
}.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);