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

一、引子

JUnit源碼是我仔細(xì)閱讀過(guò)的第一個(gè)開(kāi)源項(xiàng)目源碼。閱讀高手寫(xiě)的代碼能學(xué)到一些好的編程風(fēng)格和實(shí)現(xiàn)思路,這是提高自己編程水平行之有效的方法,因此早想看看這些赫赫有名的框架是怎么回事了。拿簡(jiǎn)單的JUnit下手,也算開(kāi)始自己的源碼分析之路。

JUnit作為的單元測(cè)試框架,由兩位業(yè)界有名人士協(xié)力完成,已經(jīng)經(jīng)歷了多次版本升級(jí)(了解JUnit基礎(chǔ)、JUnit實(shí)踐)。JUnit總體來(lái)說(shuō)短小而精悍,有不少值得我們借鑒的經(jīng)驗(yàn)在里面;但是也有一些不足存在,當(dāng)然這對(duì)于任何程序來(lái)說(shuō)都是難免的。

下面我們將從整體(宏觀)和細(xì)節(jié)(微觀)兩方面來(lái)分析JUnit源碼,以下分析基于3.8.1版。

二、宏觀——架構(gòu)與模式

打開(kāi)源碼文件,你會(huì)發(fā)現(xiàn)JUnit源碼被分配到6個(gè)包中:junit.awtui、junit.swingui、junit.textui、junit.extensions、junit.framework、junit.runner。其中前三個(gè)包中包含了JUnit運(yùn)行時(shí)的入口程序以及運(yùn)行結(jié)果顯示界面,它們對(duì)于JUnit使用者來(lái)說(shuō)基本是透明的。junit.runner包中包含了支持單元測(cè)試運(yùn)行的一些基礎(chǔ)類(lèi)以及自己的類(lèi)加載器,它對(duì)于JUnit使用者來(lái)說(shuō)是完全透明的。

剩下的兩個(gè)包是和使用JUnit進(jìn)行單元測(cè)試緊密聯(lián)系在一起的。其中junit.framework包含有編寫(xiě)一般JUnit單元測(cè)試類(lèi)必須是用到的JUnit類(lèi);而junit.extensions則是對(duì)framework包在功能上的一些必要擴(kuò)展以及為更多的功能擴(kuò)展留下的接口。

JUnit提倡單元測(cè)試的簡(jiǎn)單化和自動(dòng)化。這要求JUnit的使用要簡(jiǎn)單化,而且要很容易的實(shí)現(xiàn)自動(dòng)化測(cè)試。整個(gè)JUnit的設(shè)計(jì)大概也是遵循這個(gè)前提吧。整個(gè)框架的骨干僅有三個(gè)類(lèi)組成。

如果你掌握了TestCase、TestSuite、BaseTestRunner的工作方式,那么你可以隨心所欲的編寫(xiě)測(cè)試代碼了。

下面我們來(lái)看看junit.framework中類(lèi)之間的關(guān)系,下圖是我根據(jù)源代碼分析出來(lái)的,大部分關(guān)系都表示了出來(lái)。

先來(lái)看看各個(gè)類(lèi)的職責(zé)。Assert類(lèi)提供了JUnit使用的一整套的斷言,這套斷言都被TestCase繼承下來(lái),Assert也變成了透明的。Test接口是為了統(tǒng)一TestCase和TestSuite的類(lèi)型;而TestCase里面提供了運(yùn)行單元測(cè)試類(lèi)的方法;在TestSuite中則提供了加載單元測(cè)試類(lèi),檢驗(yàn)測(cè)試類(lèi)格式等等的方法。TestResult故名思意是提供存放測(cè)試結(jié)果的地方,但是在JUnit中它還帶有一點(diǎn)控制器的功能。

在這里指出其中我認(rèn)為有些不妥的地方。圖上TestCase和TestResult之間是雙向的依賴(lài)關(guān)系,而在UML類(lèi)圖的關(guān)系中指出:依賴(lài)關(guān)系總是單向的。讓我們來(lái)看看這這個(gè)可疑的地方。

TestCase中的代碼:

/**

* Runs the test case and collects the results in TestResult.

*/

public void run(TestResult result) {

//調(diào)用了result中的run方法,

//TestResult按照名稱(chēng)來(lái)看應(yīng)該是一個(gè)記錄測(cè)試結(jié)果的類(lèi),怎么還能run?

       result.run(this);

}

相應(yīng)得TestResult中的代碼:

/**

* Runs a TestCase.

*/

protected void run(final TestCase test) {

       //開(kāi)始測(cè)試

       startTest(test);

       //這個(gè)匿名內(nèi)類(lèi)的使用一會(huì)再講

       Protectable p= new Protectable() {

              public void protect() throws Throwable {

                     //天那,這里又調(diào)用了TestCase里面的runBare方法

                     test.runBare();

              }

       };

       runProtected(test, p); //這個(gè)方法是要執(zhí)行上面制定的匿名內(nèi)類(lèi)

       endTest(test);

}

TestResult中runProtected方法:

public void runProtected(final Test test, Protectable p) {

       try {

              p.protect();

       }

       catch (AssertionFailedError e) {

              addFailure(test, e);              //給TestResult添加失敗記錄

       }

       catch (ThreadDeath e) { // don't catch ThreadDeath by accident

              throw e;

       }

       catch (Throwable e) {

 

              addError(test, e);        //給TestResult添加出錯(cuò)記錄

       }

}

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