一、 TestRunner.doRun(Test suite,Boolean wait)方法
1、 創建一個TestResult對象,該對象是實際測試過程中的調度員。他不僅存儲了所有測試的結果,調用中的測試方法,并將結果送給ResultPrinter對象,來打印結果。
2、 將生成的ResultPrinter對象設置到TestResult對象中。
3、 取得開始時間。
4、 調用Test.run(TestResult)方法。
5、 取得結束時間。
6、 打印測試結果。
7、 判斷是否需要等待結束指令,如果需要,等調用“System.in.read()”等待結束指令。
二、 Test.run(TestResult)方法—TestCase實現
Test接口是JUnit框架中最重要的兩個接口之一,他抽象了所有測試載體的行為,包括兩個方法,一個獲取測試數目的countTestCases(),方法,一個運行測試的run(TestResult)方法。
在JUnit框架中,有兩個類顯現了這個接口。一個是只能容納單個測試的TestCase對象,這里之所以用對象是因為在我們自己實現的TestCase子類中可以有多個測試方法,但是在JUnit的實際運行中,每個TestCase對象只容納一個測試方法。
在TestCase的run(TestResult)方法中,會將實際的運行測試委派給TestResult的run(TestCase)方法,而
TestResult方法又會反過來調用TestCase的runBare()方法,將測試運行的結果放入到對應的Vector中,并通知所有設定的
TestListener,在這里就是在初始化是設定的ResultPrinter對象。
在TestCase的runBare()方法中,實際上順序調用初始化setUp()方法,實行測試runTest()方法,清除tearDown()方法三個方法。
TestCase實現的countTestCases()方法只返回1。
三、 Test.run(TestResult)方法—TestSuite實現
在JUnit框架中Test接口的另一個實現就是TestSuite類,TestSuite類可以說是實現了Test接口的Test的聚集,主要用來給容
納多個測試方法的類。在TestSuite類的內部有個Vector實例來容納這個TestSuite中所有的TestCase對象。
在
JUnit框架中,對Test接口的實現邏輯是一個比較有意思的東西。特別是TestCase類,他并沒有像我們想的那樣在run
(TestResult)方法中,利用反射調用子類中每個以“test”開頭的方法,而是在TestSuite類中解析好方法名以后傳遞給了
TestCase對象,使得每個TestCase對象只能容納一個測試方法,并針對這個測試方法調用初始化setUp()方法和清除tearDown()
方法。
我覺得這樣并不能達到“在一個TestCase中所有測試方法中公用的變量抽出為類級的變量,然后在setUp()方法中一起初始
化”。這樣的話我們就沒有必要在子類中聲明類變量,方正setUp()方法時針對每個測試方法,我們還不如直接將所有的變量放到測試方法,省得代碼變得這
里一塊,那里一塊的。真不知道Erich Gamma和Kent Back兩個高人是咋想的,有明白的希望也能給提個醒!
還是言歸正題,
話說在TestSuite實現的run(TestResult)方法中,他將所有調用每個Vector中每個Test的run(TestResult)方
法。 TestSuite實現的countTestCases()方法返回包含的Test的個數。
四、 TestListener接口
JUnit框架中有兩個重要的接口,一個是上面介紹的Test接口,下面就介紹另一個重要的接口—TestListener接口。
Test
接口抽象了所有測試載體的行為,而TestListener接口抽象了所有測試監聽者的行為,他包括兩個添加錯誤和失敗的方法:addError
(Test,Throwable)和addFailure(Test,AssertionFailedError)方法,開始測試startTest
(Test)方法,結束測試endTest(Test)方法。
在JUnit框架中有兩個類實現了這個接口,一個負責結果打印的ResultPrinter類,一個是所有TestRunner的基礎類BaseTestRunner類。
五、 ResultPrinter類
ResultPrinter類負責所有測試結果的打印,他有兩個類變量,一個是fColumn負責紀錄測試的數目,當到四十個時換行,在從零計數。Fwriter是一個PrintSteam對象負責結果的打印。
ResultPrinter實現的startTest(Test)中,完成測試數目的統計和換行,并打印出我們熟悉的”.”。 ResultPrinter實現的addError()方法和addFailure()方法只是打印出對應“E”和“F”。
ResultPrinter實現的ednTest(Test)中,什么也沒有做。
ResultPrinter
類中另一個重要的方法是print(TestResult,runTime)方法,他包括四個部分printHeader(runTime)打印所用時
間,printErrors(TestResult)打印所有錯誤,printFailures(TestResult)打印所有失敗,
printFooter(TestResult)打印結果,也就是“OK (100 test)”。
這里在啰嗦幾句JUnit框架中的Error和Failure,Error是在我們的測試方法中報出來的異常,而Failure是我們使用assertXX()方法,判斷失敗而報出的異常。
六、 TestRunner類
BaseTestRunner
類中,將TestListener接口的四個方法都委派給子類實現,而在TestRunner類中,這些方法中又什么都沒有做,我想可能是當初想用
TestRunner來實現測試結果打印,可是后來發現應該用一個單獨的類來處理所有在TestRunner類中就沒有實現這些方法。不過我想
TestRuner類中實現TestListener接口還是有一點用處的,比如想在一個類中集成多個TestRunner。
七、 Assert類
最后說說測試方法中必須的assertXX()方法,所有這些方法都放在一個叫Assert的類中,因為所有的測試方法的執行都在TestCase類中,
所以TestCase類繼承了Assert類。 Assert類也沒有什么好說的就是一堆assertXX()方法。
八、 TestResult類
TestResult
類中用兩個Vector來記錄測試的結果fErrors和fFailues。用一個Vector來存放所有的TestListener。一個整數存放測試
的數目,一個布爾變量存放停止標志。總覺得TestResult類的實現有點別扭,感覺上他應該是一個存放測試結果的類,可是JUnit的實現中總覺得有
點像控制器,由他調用TestCase中的測試方法總覺得別扭。
九、 系統結構總結
看JUnit框架有兩個感覺,第一個“小”;第二個“實用”。可能平時自己在工作中也實現過類似的功能,可是并沒有仔細想個它的通用性,以及從整個框架上的結構上系統的考慮。Erich Gamma和Kent Back兩個高人---高人真高!
Test
接口的抽象和實現典型的合成模式的應用,間接自然。輕描淡寫一個清晰的樹結構就出來了。
TestListener接口總覺得有點別扭。可能單獨的抽象出TestResult接口更好看。要是在多一個控制器接口,可能整個框架看起來更好看。要
求怎么怎么多,其實我覺得這樣完全實現了功能并且提供了很好的擴展性,可是畢竟是高人寫的,所以我們的要求當然要高點。