您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 > junit
JUnit源碼分析
作者:網(wǎng)絡轉(zhuǎn)載 發(fā)布時間:[ 2013/1/18 13:59:32 ] 推薦標簽:

為什么JUnit里面會出現(xiàn)這樣奇怪的依賴關(guān)系,還有違反單一職責原則的TestResult?當我看到junit.extentions包中的TestSetup時,也許我猜到了作者的用意。我們來看下TestSetup中有關(guān)的代碼:

public void run(final TestResult result) {

       //又看到了上面類似的匿名內(nèi)部類

       Protectable p= new Protectable() {

              public void protect() throws Exception {

                     //不過這個內(nèi)部類里面的實現(xiàn)有所不同

      setUp();

                     basicRun(result);

                     tearDown();

              }

       };

       //調(diào)用了TestResult中的runProtected方法來執(zhí)行上面的實現(xiàn)

       result.runProtected(this, p);

}

這個類的產(chǎn)生是為了彌補TestCase類的一個小小的缺陷(具體請見下部分)。注意到在這個類里面也有和TestResult類似的匿名內(nèi)部類。這種匿名內(nèi)部類全是Protected接口的無名實現(xiàn),這里的目的我認為有兩點:

1)        由于內(nèi)部類可以在接下來的情景中完全不可見,而且不被任何人使用,因此也隱藏了接口的實現(xiàn)細節(jié)。

2)        為了提高可重用性,而使用內(nèi)部類比較快捷。這樣不管你protect方法里面具體執(zhí)行什么,對它錯誤、失敗、異常捕捉的代碼(TestResult中的runProtected方法)可以重用了。

這也正是為什么會出現(xiàn)上面那樣奇怪的依賴關(guān)系:為了復用,要讓runProtected方法放在一個TestCase和TestSetup都能調(diào)用的地方。

不過我認為為了復用而破壞了系統(tǒng)良好的結(jié)構(gòu)和可讀性,是需要仔細斟酌的。JUnit這樣的設計估計是為了以后框架多次擴展后的重用考慮的。

說完了讓我費解的問題。談談我覺得JUnit框架中讓我感嘆的地方,那是小小的框架里面使用了很多設計模式在里面。而這些模式的使用也正是為了體現(xiàn)出整個框架結(jié)構(gòu)的簡潔、可擴展。我將粗略的分析如下(模式應用的詳細內(nèi)容請關(guān)注我關(guān)于設計模式的文章)。先看看在junit.framework里面使用的設計模式。

命令模式:作為輔助單元測試的框架,開發(fā)人員在使用它的時候,應該僅僅關(guān)心測試用例的編寫,JUnit只是一個測試用例的執(zhí)行器和結(jié)果查看器,不應該關(guān)心太多關(guān)于這個框架的細節(jié)。而對于JUnit來說,它并不需要知道請求TestCase的操作信息,僅把它當作一種命令來執(zhí)行,然后把執(zhí)行測試結(jié)果發(fā)給開發(fā)人員。命令模式正是為了達到這種送耦合的目的。

組合模式:當系統(tǒng)的測試用例慢慢變得多起來,挨個運行測試用例成了一個棘手的問題。作為一個方便使用的單元測試框架,這一點是必須解決的。因此JUnit里面提供了TestSuite的功能,它允許將多個測試用例放到一個TestSuite里面來一次執(zhí)行;而且要進一步的支持TestSuite里面套TestSuite的功能。使用組合模式能夠很好的解決這個問題。

在上面我們已經(jīng)提到了junit.extentions包中的內(nèi)容TestSetup。來看看整個包的結(jié)構(gòu)吧。

先簡要的介紹下包中各個類的功能。ActiveTestSuite對TestSuite進行了改進,使得每個test運行在一個單獨的線程里面,并且只到所有的線程都結(jié)束了才會結(jié)束整個測試。ExceptionTestCase是對TestCase進行的改進,可以方便的判斷測試類是否拋出了期望的異常。而剩下的三個類,大概你看的出來是使用了裝飾模式來設計的。其中TestDecorator為具體裝飾類制定好了使用規(guī)則,RepeatedTest和TestSetup則是具體實現(xiàn)的裝飾類。

那為什么extentions包中ActiveTestSuite和ExceptionTestCase沒有使用裝飾模式呢?原因在于裝飾模式在結(jié)構(gòu)上要求存在類似于組合模式的遞歸。而對于已有的TestCase和TestSuite來說,直接繼承它們要比構(gòu)建一個新的遞歸結(jié)構(gòu)要來得快得多而且簡單;并且這些增強功能都只是針對TestCase或者TestSuite。使用了裝飾模式來擴展的類與以上不同的是,它們功能的增強是針對任何Test實現(xiàn)的。如果不采用裝飾模式同樣的功能要為TestCase、TestSuite以及以后的其他Test實現(xiàn)分別寫出子類。因此使用裝飾模式能夠很巧妙的解決這個問題。

下面來介紹下junit.runner包。上面已經(jīng)提到,對于JUnit使用者來說,它可說是完全透明的,這個包里面提供了JUnit自己的測試類加載。下面是包中所有類的關(guān)系圖。

沒有什么好講的,都是使用反射機制來將測試類加載進來,還有讀取properties文件的操作。如果想學習下反射機制的應用可以閱讀這部分的源碼。

剩下的三個包這里也不作介紹,大部分的內(nèi)容都是GUI的繪制(當然junit.textui包除外)。

JUnit中還使用了觀察者模式來完成單元測試結(jié)果的自動更新(詳細內(nèi)容請見我關(guān)于觀察者模式的文章)。

這樣,對JUnit的整體框架有了全面的認識。總體來說各個包分工明確,設計上采用了必要的設計模式來增強了擴展性和重用性,很值得學習和借鑒。

三、微觀——執(zhí)行流程與代碼風格


來過一遍JUnit的執(zhí)行流程吧,這樣你能對JUnit有個清晰的認識,雖然作為一個使用者這完全是不必要的。從《JUnit in Action》直接拿來一張JUnit流程圖。

哦,也許你看暈了,我來當下導游好了。上面已經(jīng)提到了TestRunner是BaseTestRunner的子類,在三個不同的ui包中各有一個TestRunner。這里我們僅以junit.textui包中的為例。

TestRunner作為入口程序是怎么被啟動的呢?習慣了使用容器的我們現(xiàn)在也許很少考慮這個問題。那我們在TestRunner類里面找找吧,你看,你發(fā)現(xiàn)了這個:

public static void main(String args[])

這不是我們寫小桌面程序時經(jīng)常打交道的main方法么?對,這么簡單。

上一頁123下一頁
軟件測試工具 | 聯(lián)系我們 | 投訴建議 | 誠聘英才 | 申請使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權(quán)所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd