JUnit源码解析(2)
发表于:2016-10-04来源:saymagic作者:saymagic点击数:
标签:junit
} 可以看到,整个构造函数大致都在做一些验证和初始化的工作,需要引起我们注意的应该是scanAnnotatedMembers方法: protected void scanAnnotatedMembers(MapClass? exte
}
可以看到,整个构造函数大致都在做一些验证和初始化的工作,需要引起我们注意的应该是scanAnnotatedMembers方法:
protected void scanAnnotatedMembers(Map<Class<? extends Annotation>, List<FrameworkMethod>> methodsForAnnotations, Map<Class<? extends Annotation>, List<FrameworkField>> fieldsForAnnotations) {
for (Class<?> eachClass : getSuperClasses(clazz)) {
for (Method eachMethod : MethodSorter.getDeclaredMethods(eachClass)) {
addToAnnotationLists(new FrameworkMethod(eachMethod), 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.evaluate();
} 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 evaluate() {
runChildren(notifier);
}
};
}
childrenInvoker返回的是一个Statement,看它的evaluate方法,其调用的是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() {