步驟(測(cè)試代碼中含有“suite”):
1. Main方法先new TestResult,然后待用start方法;start方法中主要做了兩件事情,初始化解析加載測(cè)試集,即getTest;另外一件是執(zhí)行調(diào)度測(cè)試集并記錄測(cè)試結(jié)果,即doRun
2. 在start方法中調(diào)用BaseTestRunner中的getTest(),在getTest中,通過(guò)反射檢查測(cè)試代碼中是否含有“suite”關(guān)鍵字,如果有則按有“suite”模式執(zhí)行,上面已經(jīng)說(shuō)明過(guò)來(lái)
3. 如果沒(méi)有則,創(chuàng)建一個(gè)測(cè)試TestSuite
new TestSuite(testClass)
4. 將一個(gè)個(gè)testSuite對(duì)象加載到測(cè)試集中
5. 通過(guò)反射的方法,從測(cè)試代碼中解析出所有測(cè)試方法,然后篩選出test開(kāi)頭,且參數(shù)為空,類型為viod的方法,找到待測(cè)試的方法(6中篩選過(guò)濾),然后通過(guò)反射后newInstance一個(gè)個(gè)測(cè)試方法,轉(zhuǎn)化成Junit的測(cè)試用例(testcase)
6. 將Junit轉(zhuǎn)化的測(cè)試用例加載fTest測(cè)試集中,待執(zhí)行
另外:注意一點(diǎn),當(dāng)測(cè)試代碼中含有構(gòu)造函數(shù),時(shí),在上圖中第5步中,會(huì)判斷是否含有構(gòu)造函數(shù),如果有增加兩步,則按照下圖所示執(zhí)行,
(1) 通過(guò)反射找到構(gòu)造函數(shù),
(2) 通過(guò)構(gòu)造函數(shù)初始化構(gòu)造對(duì)象,即tecase
1.2 運(yùn)行調(diào)度階段
Junit在執(zhí)行調(diào)度測(cè)試代碼過(guò)程中比較簡(jiǎn)單,主要有兩種情況,一種情況按照正常的情況調(diào)用,另外一種情況,如果代碼中需要重復(fù)執(zhí)行某個(gè)測(cè)試方法時(shí),則需要調(diào)度repeateTest類
下圖先簡(jiǎn)單說(shuō)明下正常情況
其步驟如下:
1. 在3.1中初始化解析完成測(cè)試對(duì)象后,需要調(diào)度執(zhí)行測(cè)試測(cè)試代碼,在start方法中調(diào)用doRun方法
2. 創(chuàng)建一個(gè)測(cè)試結(jié)果集TestResult,初始化TestResult中的主要參數(shù)fFailures、fErrors、fListener、fRunTests、fStop
3. TestResult調(diào)用TestSuite中的run方法,并且循環(huán)找出結(jié)果集中的所有測(cè)試對(duì)象,即Juint中的testcase
4. TestSuite調(diào)用testRun方法
5. testRun方法調(diào)用TestCase中的run方法
6. run中調(diào)用了runProtected方法,并通過(guò)內(nèi)部類實(shí)現(xiàn)對(duì)protect()
7. 通過(guò)protect()調(diào)用runBare()方法
8. 從第九步以后調(diào)用了測(cè)試函數(shù),完成了整個(gè)執(zhí)行過(guò)程(不包括執(zhí)行結(jié)果捕捉和記錄)
兩外,對(duì)于測(cè)試代碼中含有“RepeatedTest”關(guān)鍵字的,執(zhí)行流程稍有不同,如下圖,其過(guò)程不一一解釋,可以結(jié)合上面的解釋了解下。
suite.addTest(new RepeatedTest(new CalculatorTest("testSubtract"), 3));
1.3 運(yùn)行結(jié)果捕捉及記錄階段
執(zhí)行結(jié)果捕捉和記錄是測(cè)試過(guò)程非常重要的一部分,所以把這部分過(guò)程單獨(dú)拿出來(lái)說(shuō)明下,前幾部分都非常簡(jiǎn)單,
第四步是通過(guò)反射調(diào)用測(cè)試方法,測(cè)試方法再通過(guò)調(diào)用被測(cè)代碼,然后產(chǎn)生預(yù)期結(jié)果,
第五步是通過(guò)斷言方法,實(shí)現(xiàn)對(duì)實(shí)際執(zhí)行結(jié)果和預(yù)期結(jié)果比對(duì),
第六步如果預(yù)期結(jié)果與實(shí)際結(jié)果不相同則調(diào)用failNotEquals
第八步如果錯(cuò)誤,調(diào)用fail方法,實(shí)現(xiàn)返回throw new AssertionFailedError(message),異常
后面幾步通過(guò)異常捕捉捕捉錯(cuò)誤,通過(guò)TestResult類中的addFailure進(jìn)行處理實(shí)現(xiàn)。在這塊Junit通過(guò)觀察者模式實(shí)現(xiàn)對(duì)測(cè)試結(jié)果的動(dòng)態(tài)捕捉和記錄(關(guān)于觀察者模式后面繼續(xù)討論)。具體過(guò)程詳見(jiàn)下圖
關(guān)于錯(cuò)誤的捕捉(Error)的實(shí)現(xiàn)和Fail的比較像,在這不?嗦了。
兩外,在這說(shuō)明下,JUnit中的兩個(gè)概念錯(cuò)誤(error)與失敗(failure)
1) 錯(cuò)誤指的是代碼中拋出了異常等影響代碼正常執(zhí)行的情況,比如拋出了ArrayIndexOutOfBoundsException,這叫做錯(cuò)誤。
2) 失敗指的是我們斷言所期待的結(jié)果與程序?qū)嶋H執(zhí)行的結(jié)果不一致,或者是直接調(diào)用了fail()方法,這叫做失敗。