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() {