JUnit源碼解析(4)
發表于:2016-10-04來源:saymagic作者:saymagic點擊數:
標簽:junit
return befores.isEmpty() ? statement : new RunBefores(statement, befores, target); } 這個函數里首先拿到了所有被@Before標注的方法,將其封裝為RunBefores,我們看下其構造函數
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 evaluate() throws Throwable {
for (FrameworkMethod before : befores) {
before.invokeExplosively(target);
}
next.evaluate();
}
很是明了,evaluate執行時,首先將before方法全部invoke來執行,然后才調用原始statement的evaluate方法。其余幾個函數與此類似,感興趣可以繼續查看。
如此,我們就明白了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.evaluate();
} catch (AssumptionViolatedException e) {
eachNotifier.addFailedAssumption(e);
} catch (Throwable e) {
eachNotifier.addFailure(e);
} finally {
eachNotifier.fireTestFinished();
}
}
非常簡單,直接執行了statement的evaluate方法,需要注意的是這里的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注解的方法只能是static的。
如上,我們分析了BlockJUnit4ClassRunner的運行流程,也就是說當測試類為一個的時候JUnit是如何工作的。前文也提到過,ParentRunner還有一個子類Suite,表示需要運行一組測試,BlockJUnit4ClassRunner的一個運行單元為FrameworkMethod,而Suite的一個運行單元為Runner,我們看其runChild方法: