您的位置:軟件測(cè)試 > 開(kāi)源軟件測(cè)試 > 開(kāi)源單元測(cè)試工具 > junit
利用Ant和JUnit進(jìn)行增量開(kāi)發(fā)
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時(shí)間:[ 2013/1/31 13:59:12 ] 推薦標(biāo)簽:

  軟件開(kāi)發(fā)習(xí)慣中一個(gè)細(xì)微更改都可能會(huì)對(duì)軟件質(zhì)量產(chǎn)生巨大改進(jìn)。將單元測(cè)試合并到開(kāi)發(fā)過(guò)程中,然后從長(zhǎng)遠(yuǎn)角度來(lái)看它可以節(jié)省多少時(shí)間和精力。本文通過(guò)使用代碼樣本說(shuō)明了單元測(cè)試的種種好處,特別是使用 Ant 和 JUnit 帶來(lái)的各種方便。

  測(cè)試是大型開(kāi)發(fā)過(guò)程中的基本原則之一。在任何職業(yè)中,驗(yàn)證都是一個(gè)重要部分。醫(yī)生要通過(guò)驗(yàn)血來(lái)確診。波音公司在研制 777 的過(guò)程中對(duì)飛機(jī)的每個(gè)組件都進(jìn)行了精心測(cè)試。為什么軟件開(kāi)發(fā)應(yīng)該例外呢?

  以前,由于在應(yīng)用程序中將 GUI 和商業(yè)邏輯緊密聯(lián)系在一起,這限制了創(chuàng)建自動(dòng)測(cè)試的能力。當(dāng)我們學(xué)會(huì)通過(guò)抽象層將商業(yè)邏輯從界面中分離出來(lái)時(shí),各個(gè)單獨(dú)代碼模塊的自動(dòng)測(cè)試替代了通過(guò) GUI 進(jìn)行的手工測(cè)試。

  現(xiàn)在,集成開(kāi)發(fā)環(huán)境 (IDE) 能在您輸入代碼的同時(shí)顯示錯(cuò)誤,對(duì)于在類(lèi)中快速查找方法具有智能探測(cè)功能,可以利用語(yǔ)法結(jié)構(gòu)生成彩色代碼,而且具有許多其它功能。因此,在編譯更改過(guò)的代碼之前,您已經(jīng)全盤(pán)考慮了將構(gòu)建的類(lèi),但您是否考慮過(guò)這樣的修改會(huì)破壞某些功能呢?

  每個(gè)開(kāi)發(fā)者都碰到過(guò)更改“臭蟲(chóng)”。代碼修改過(guò)程可能會(huì)引入“臭蟲(chóng)”,而如果通過(guò)用戶(hù)界面手工測(cè)試代碼的話(huà),在編譯完成之前是不會(huì)發(fā)現(xiàn)它的。然后,您要花費(fèi)幾天的時(shí)間追蹤由更改所引起的錯(cuò)誤。近在我做的一個(gè)項(xiàng)目中,當(dāng)我把后端數(shù)據(jù)庫(kù)由 Informix 更改到 Oracle 時(shí)遇到了這種情況。大部分更改都十分順利,但由于數(shù)據(jù)庫(kù)層或使用數(shù)據(jù)庫(kù)層的系統(tǒng)缺少單元測(cè)試,從而導(dǎo)致將大量時(shí)間花費(fèi)在嘗試解決更改“臭蟲(chóng)”上。我花了兩天的時(shí)間查到別人代碼中的一個(gè)數(shù)據(jù)庫(kù)語(yǔ)法更改。(當(dāng)然,那個(gè)人仍是我的朋友。)

  盡管測(cè)試有許多好處,但一般的程序員對(duì)測(cè)試都不太感興趣,開(kāi)始時(shí)我也沒(méi)有。您聽(tīng)到過(guò)多少次“它編譯了,所以它一定能用”這種言論?但“我思,故我在”這種原則并 不 適用于高質(zhì)量軟件。要鼓勵(lì)程序員測(cè)試他們的代碼,過(guò)程必須簡(jiǎn)單無(wú)痛。

  本文從某人學(xué)習(xí)用 Java語(yǔ)言編程時(shí)所寫(xiě)的一個(gè)簡(jiǎn)單的類(lèi)開(kāi)始。然后,我會(huì)告訴您我是如何為這個(gè)類(lèi)編寫(xiě)單元測(cè)試,以及在編寫(xiě)完它以后又是如何將單元測(cè)試添加到構(gòu)建過(guò)程中的。后,我們將看到將“臭蟲(chóng)”引入代碼時(shí)發(fā)生的情況。

  從一個(gè)典型類(lèi)開(kāi)始
  第一個(gè)典型的 Java 程序一般都包含一個(gè)打印 "Hello World" 的 main() 。在清單 1 中,我創(chuàng)建了一個(gè) HelloWorld 對(duì)象的實(shí)例并調(diào)用 sayHello() 方法,該方法會(huì)打印這句習(xí)慣說(shuō)法。

  清單 1. 我的第一個(gè) Java 應(yīng)用程序 "Hello world"

/* * HelloWorld.java * My first java program */ class HelloWorld { /** * Print "Hello World" */ void sayHello() { System.out.println("Hello World"); } /** * Test */ public static void main( String[] args ) { HelloWorld world = new HelloWorld(); world.sayHello(); } }

  main() 方法是我的測(cè)試。哦噢!我將代碼、文檔、測(cè)試和樣本代碼包含在了一個(gè)模塊中。保佑 Java!但隨著程序越變?cè)酱螅@種開(kāi)發(fā)方法很快開(kāi)始顯現(xiàn)出了缺陷:

    混亂
    類(lèi)接口越大, main() 越大。類(lèi)可能僅僅因?yàn)檎5臏y(cè)試而變得非常龐大。
    代碼膨脹
    由于加入了測(cè)試,所以產(chǎn)品代碼比所需要的要大。但我不想交付測(cè)試,而只想交付產(chǎn)品。
    測(cè)試不可靠
    既然 main() 是代碼的一部分, main() 對(duì)其他開(kāi)發(fā)者通過(guò)類(lèi)接口無(wú)法訪問(wèn)的私有成員和方法享有訪問(wèn)權(quán)。出于這個(gè)原因,這種測(cè)試方法很容易出錯(cuò)。
    很難自動(dòng)測(cè)試
    要進(jìn)行自動(dòng)測(cè)試,我仍然必須創(chuàng)建另一程序來(lái)將參數(shù)傳遞給 main() 。

  類(lèi)開(kāi)發(fā)
  對(duì)我來(lái)說(shuō),類(lèi)開(kāi)發(fā)是從編寫(xiě) main() 方法開(kāi)始的。我在編寫(xiě) main() 的時(shí)候定義類(lèi)和類(lèi)的用法,然后實(shí)現(xiàn)接口。它的一些明顯的缺陷也開(kāi)始顯現(xiàn)出來(lái)。一個(gè)缺陷是我傳遞給 main() 來(lái)執(zhí)行測(cè)試的參數(shù)個(gè)數(shù)。其次, main() 本身在進(jìn)行調(diào)用子方法、設(shè)置代碼等操作時(shí)變得很混亂。有時(shí) main() 會(huì)比類(lèi)實(shí)現(xiàn)的其余部分還要大。

  更簡(jiǎn)單的過(guò)程
我原來(lái)的做法有一些很明顯的缺陷。因此,讓我們看看有什么別的方法可以使問(wèn)題簡(jiǎn)化。我仍然通過(guò)接口設(shè)計(jì)代碼并給出應(yīng)用示例,正如原來(lái)的 main() 一樣。不同的是我將代碼放到了另一個(gè)單獨(dú)的類(lèi)中,而這個(gè)類(lèi)恰好是我的“單元測(cè)試”。這種技術(shù)有以下幾點(diǎn)好處:

    設(shè)計(jì)類(lèi)的一種機(jī)制
    因?yàn)槭峭ㄟ^(guò)接口進(jìn)行開(kāi)發(fā),所以不太可能利用類(lèi)的內(nèi)部功能。但因?yàn)槲沂悄繕?biāo)類(lèi)的開(kāi)發(fā)者,我有到其內(nèi)部工作的“窗口”,所以測(cè)試并不是個(gè)真正的黑箱。僅憑這一點(diǎn)足夠推斷出需要開(kāi)發(fā)者本人在編寫(xiě)目標(biāo)類(lèi)的同時(shí)負(fù)責(zé)測(cè)試的開(kāi)發(fā),而不是由其他任何人代勞。
    類(lèi)用法的示例
    通過(guò)將示例從實(shí)現(xiàn)中分離出來(lái),開(kāi)發(fā)者可以更快地提高速度,而且再不用在源代碼上糾纏不清。這種分離還有助于防止開(kāi)發(fā)者利用類(lèi)的內(nèi)部功能,因?yàn)檫@些功能將來(lái)可能已經(jīng)不存在了。
    沒(méi)有類(lèi)混亂的 main()
    我不再受到 main() 的限制了。以前我得將多個(gè)參數(shù)傳遞給 main() 來(lái)測(cè)試不同的配置,F(xiàn)在我可以創(chuàng)建許多單獨(dú)的測(cè)試類(lèi),每一個(gè)都維護(hù)各自的設(shè)置代碼。

  接下來(lái)我們將這個(gè)單獨(dú)的單元測(cè)試對(duì)象放入構(gòu)建過(guò)程中。這樣,我們可以提供自動(dòng)確認(rèn)過(guò)程的方法。

    確保所做的任何更改都不會(huì)對(duì)其他人產(chǎn)生不利影響。
    我們?cè)谶M(jìn)行源碼控制之前可以測(cè)試代碼,而無(wú)需等待匯編測(cè)試或在夜晚進(jìn)行的構(gòu)建測(cè)試。這有助于盡早捕捉到“臭蟲(chóng)”,從而降低產(chǎn)生高質(zhì)量代碼的成本。
    通過(guò)提供增量測(cè)試過(guò)程,我們提供了更好的實(shí)現(xiàn)過(guò)程。如同 IDE 幫助我們?cè)谳斎霑r(shí)捕捉到語(yǔ)法或編譯“臭蟲(chóng)”一樣,增量單元測(cè)試也幫助我們?cè)跇?gòu)建時(shí)捕捉到代碼更改“臭蟲(chóng)”。

  使用 JUnit 自動(dòng)化單元測(cè)試
  要使測(cè)試自動(dòng)化,您需要一個(gè)測(cè)試框架。您可以自己開(kāi)發(fā)或購(gòu)買(mǎi),也可以使用某些開(kāi)放源代碼工具,例如 JUnit。我選擇 JUnit 出于以下幾個(gè)原因:

    不需要編寫(xiě)自己的框架。
    它是開(kāi)放源代碼,因此不需要購(gòu)買(mǎi)框架。
    開(kāi)放源代碼社區(qū)中的其他開(kāi)發(fā)者會(huì)使用它,因此可以找到許多示例。
    它可以讓我將測(cè)試代碼與產(chǎn)品代碼分開(kāi)。
    它易于集成到我的構(gòu)建過(guò)程中。

  測(cè)試布局
  圖 1 顯示了使用樣本 TestSuite 的 JUnit TestSuite 布局。每個(gè)測(cè)試都由若干單獨(dú)的測(cè)試案例構(gòu)成。每個(gè)測(cè)試案例都是一個(gè)單獨(dú)的類(lèi),它擴(kuò)展了 TestClass 類(lèi)并包含了我的測(cè)試代碼,即那些曾在 main() 中出現(xiàn)的代碼。在該例中,我向 TestSuite 添加了兩個(gè)測(cè)試:一個(gè)是 SkeletonTest,我將它用作所有新類(lèi)和 HelloWorld 類(lèi)的起點(diǎn)。

圖 1. TestSuite 布局

  測(cè)試類(lèi) HelloWorldTest.java

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