亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
12下一頁
最近訪問板塊 發(fā)新帖
查看: 35676 | 回復(fù): 18
打印 上一主題 下一主題

應(yīng)用JUnit實施單元測試 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2003-12-03 10:21 |只看該作者 |倒序瀏覽
應(yīng)用JUnit實施單元測試(原創(chuàng)作者:eric )


(獻給想保證java coding軟件質(zhì)量的朋友們)
--------------------------------------------------------------------------------

測試的概念

長期以來,我所接觸的軟件開發(fā)人員很少有人能在開發(fā)的過程中進行測試工作。大部分的項目都是在最終驗收的時候編寫測試文檔。有些項目甚至沒有測試文檔,F(xiàn)在情況有了改變。我們一直提倡UML、RUP、軟件工程、CMM,目的只有一個,提高軟件編寫的質(zhì)量。舉一個極端的例子:如果你是一個超級程序設(shè)計師,一個傳奇般的人物。(你可以一邊喝咖啡,一邊聽著音樂,同時編寫這操作系統(tǒng)中關(guān)于進程調(diào)度的模塊,而且兩天時間內(nèi)就完成了!)我真得承認,有這樣的人。(那個編寫UNIX中的vi編輯器的家伙就是這種人。)然而非常遺憾的是這些神仙們并沒有留下如何修成正果的README。所以我們這些凡人--在同一時間只能將注意力集中到若干點(據(jù)科學(xué)統(tǒng)計,我并不太相信,一般的人只能同時考慮最多7個左右的問題,高手可以達到12個左右),而不能既縱覽全局又了解細節(jié)--只能期望于其他的方式來保證我們所編寫的軟件質(zhì)量。

為了說明我們這些凡人是如何的笨。有一個聰明人提出了軟件熵(software entropy)的概念:一個程序從設(shè)計很好的狀態(tài)開始,隨著新的功能不斷地加入,程序逐漸地失去了原有的結(jié)構(gòu),最終變成了一團亂麻。你可能會爭辯,在這個例子中,設(shè)計很好的狀態(tài)實際上并不好,如果好的話,就不會發(fā)生你所說的情況。是的,看來你變聰明了,可惜你還應(yīng)該注意到兩個問題:1)我們不能指望在恐龍紀(jì)元(大概是十年前)設(shè)計的結(jié)構(gòu)到了現(xiàn)在也能適用吧。2)擁有簽字權(quán)的客戶代表可不理會加入一個新功能是否會對軟件的結(jié)構(gòu)有什么影響,即便有影響也是程序設(shè)計人員需要考慮的問題。如果你拒絕加入這個你認為致命的新功能,那么你很可能就失去了你的住房貸款和面包(對中國工程師來說也許是米飯或面條,要看你是南方人還是北方人)。

另外,需要說明的是我看過的一些講解測試的書都沒有我寫的這么有人情味(不好意思...)。我希望看到這片文章的兄弟姐妹能很容易地接受測試的概念,并付諸實施。所以有些地方寫的有些夸張,歡迎對測試有深入理解的兄弟姐妹能體察民情,并不吝賜教。

好了,我們現(xiàn)在言歸正傳。要測試,就要明白測試的目的。我認為測試的目的很簡單也極具吸引力:寫出高質(zhì)量的軟件并解決軟件熵這一問題。想象一下,如果你寫的軟件和Richard Stallman(GNU、FSF的頭兒)寫的一樣有水準(zhǔn)的話,是不是很有成就感?如果你一致保持這種高水準(zhǔn),我保證你的薪水也會有所變動。

測試也分類,白箱測試、黑箱測試、單元測試、集成測試、功能測試...。我們先不管有多少分類,如何分類。先看那些對我們有用的分類,關(guān)于其他的測試,有興趣的人可參閱其他資料。白箱測試是指在知道被測試的軟件如何(How)完成功能和完成什么樣(What)的功能的條件下所作的測試。一般是由開發(fā)人員完成。因為開發(fā)人員最了解自己編寫的軟件。本文也是以白箱測試為主。黑箱測試則是指在知道被測試的軟件完成什么樣(What)的功能的條件下所作的測試。一般是由測試人員完成。黑箱測試不是我們的重點。本文主要集中在單元測試上,單元測試是一種白箱測試。目的是驗證一個或若干個類是否按所設(shè)計的那樣正常工作。集成測試則是驗證所有的類是否能互相配合,協(xié)同完成特定的任務(wù),目前我們暫不關(guān)心它。下面我所提到的測試,除非特別說明,一般都是指單元測試。

需要強調(diào)的是:測試是一個持續(xù)的過程。也就是說測試貫穿與開發(fā)的整個過程中,單元測試尤其適合于迭代增量式(iterative and incremental)的開發(fā)過程。Martin Fowler(有點兒像引用孔夫子的話)甚至認為:“在你不知道如何測試代碼之前,就不應(yīng)該編寫程序。而一旦你完成了程序,測試代碼也應(yīng)該完成。除非測試成功,你不能認為你編寫出了可以工作的程序!蔽也⒉恢竿械拈_發(fā)人員都能有如此高的覺悟,這種層次也不是一蹴而就的。但我們一旦了解測試的目的和好處,自然會堅持在開發(fā)過程中引入測試。

因為我們是測試新手,我們也不理會那些復(fù)雜的測試原理,先說一說最簡單的:測試就是比較預(yù)期的結(jié)果是否與實際執(zhí)行的結(jié)果一致。如果一致則通過,否則失敗?聪旅娴睦樱


        //將要被測試的類
        public class Car {
            public int getWheels() {
                        return 4;
                }
        }
       
        //執(zhí)行測試的類
        public class testCar {
                public static void main(String[] args) {
                        testCar myTest = new testCar();
                        myTest.testGetWheels();
                }
               
                public testGetWheels() {
                        int expectedWheels = 4;
                        Car myCar = Car();
                        if (expectedWheels==myCar.getWheels())
                                System.out.println("test [Car]: getWheels works perfected!";
                        else
                                System.out.println("test [Car]: getWheels DOESN'T work!";       
                }
        }
       
如果你立即動手寫了上面的代碼,你會發(fā)現(xiàn)兩個問題,第一,如果你要執(zhí)行測試的類testCar,你必須必須手工敲入如下命令:

        [Windows] d:>;java testCar
           [Unix] % java testCar
       
即便測試如例示的那樣簡單,你也有可能不愿在每次測試的時候都敲入上面的命令,而希望在某個集成環(huán)境中(IDE)點擊一下鼠標(biāo)就能執(zhí)行測試。后面的章節(jié)會介紹到這些問題。第二,如果沒有一定的規(guī)范,測試類的編寫將會成為另一個需要定義的標(biāo)準(zhǔn)。沒有人希望查看別人是如何設(shè)計測試類的。如果每個人都有不同的設(shè)計測試類的方法,光維護被測試的類就夠煩了,誰還顧得上維護測試類?另外有一點我不想提,但是這個問題太明顯了,測試類的代碼多于被測試的類!這是否意味這雙倍的工作?不!1)不論被測試類-Car 的 getWheels 方法如何復(fù)雜,測試類-testCar 的testGetWheels 方法只會保持一樣的代碼量。2)提高軟件的質(zhì)量并解決軟件熵這一問題并不是沒有代價的。testCar就是代價。

我們目前所能做的就是盡量降低所付出的代價:我們編寫的測試代碼要能被維護人員容易的讀取,我們編寫測試代碼要有一定的規(guī)范。最好IDE工具可以支持這些規(guī)范。 好了,你所需要的就是JUnit。一個Open Source的項目。用其主頁上的話來說就是:“JUnit是由 Erich Gamma 和 Kent Beck 編寫的一個回歸測試框架(regression testing framework)。用于Java開發(fā)人員編寫單元測試之用!彼^框架就是 Erich Gamma 和 Kent Beck 定下了一些條條框框,你編寫的測試代碼必須遵循這個條條框框:繼承某個類,實現(xiàn)某個接口。其實也就是我們前面所說的規(guī)范。好在JUnit目前得到了大多數(shù)軟件工程師的認可。遵循JUnit我們會得到很多的支持;貧w測試就是你不斷地對所編寫的代碼進行測試:編寫一些,測試一些,調(diào)試一些,然后循環(huán)這一過程,你會不斷地重復(fù)先前的測試,哪怕你正編寫其他的類,由于軟件熵的存在,你可能在編寫第五個類的時候發(fā)現(xiàn),第五個類的某個操作會導(dǎo)致第二個類的測試失敗。通過回歸測試我們抓住了這條大Bug。


回歸測試框架-JUnit
通過前面的介紹,我們對JUnit有了一個大概的輪廓。知道了它是干什么的,F(xiàn)在讓我們動手改寫上面的測試類testCar使其符合Junit的規(guī)范--能在JUnit中運行。

        //執(zhí)行測試的類(JUnit版)
        import junit.framework.*;
       
        public class testCar extends TestCase {
               
                protected int expectedWheels;
                protected Car myCar;
               
                public testCar(String name) {
                        super(name);
                }
               
                protected void setUp() {
                        expectedWheels = 4;
                        myCar = new Car();
                }
               
                public static Test suite() {
                        /*
                         * the type safe way
                         *
                        TestSuite suite= new TestSuite();
                        suite.addTest(
                                new testCar("Car.getWheels" {
                                         protected void runTest() { testGetWheels(); }
                                }
                        );
                        return suite;
                        */
       
                        /*
                         * the dynamic way
                         */               
                        return new TestSuite(testCar.class);
                }
               
                public void testGetWheels() {
                        assertEquals(expectedWheels, myCar.getWheels());
                }
        }
       
改版后的testCar已經(jīng)面目全非。先讓我們了解這些改動都是什么含義,再看如何執(zhí)行這個測試。

1>;import語句,引入JUnit的類。(沒問題吧)

2>;繼承 TestCase ?梢詴簳r將一個TestCase看作是對某個類進行測試的方法的集合。詳細介紹請參看JUnit資料

3>;setUp()設(shè)定了進行初始化的任務(wù)。我們以后會看到setUp會有特別的用處。

4>;testGetWheeels()對預(yù)期的值和myCar.getWheels()返回的值進行比較,并打印比較的結(jié)果。assertEquals是junit.framework.Assert中所定義的方法,junit.framework.TestCase繼承了junit.framework.Assert。

5>;suite()是一個很特殊的靜態(tài)方法。JUnit的TestRunner會調(diào)用suite方法來確定有多少個測試可以執(zhí)行。上面的例子顯示了兩種方法:靜態(tài)的方法是構(gòu)造一個內(nèi)部類,并利用構(gòu)造函數(shù)給該測試命名(test name, 如 Car.getWheels ),其覆蓋的runTest()方法,指明了該測試需要執(zhí)行那些方法--testGetWheels()。動態(tài)的方法是利用內(nèi)省(reflection )來實現(xiàn)runTest(),找出需要執(zhí)行那些測試。此時測試的名字即是測試方法(test method,如testGetWheels)的名字。JUnit會自動找出并調(diào)用該類的測試方法。

6>;將TestSuite看作是包裹測試的一個容器。如果將測試比作葉子節(jié)點的話,TestSuite就是分支節(jié)點。實際上TestCase,TestSuite以及TestSuite組成了一個composite Pattern。 JUnit的文檔中有一篇專門講解如何使用Pattern構(gòu)造Junit框架。有興趣的朋友可以查看JUnit資料。

如何運行該測試呢?手工的方法是鍵入如下命令:

        [Windows] d:>;java junit.textui.TestRunner testCar
           [Unix] % java junit.textui.TestRunner testCar
       
別擔(dān)心你要敲的字符量,以后在IDE中,只要點幾下鼠標(biāo)就成了。運行結(jié)果應(yīng)該如下所示,表明執(zhí)行了一個測試,并通過了測試:

        .
        Time: 0
       
        OK (1 tests)
       
如果我們將Car.getWheels()中返回的的值修改為3,模擬出錯的情形,則會得到如下結(jié)果:
        .F
        Time: 0
        There was 1 failure:
        1) testGetWheels(testCar)junit.framework.AssertionFailedError: expected:<4>; but was:<3>;
                        at testCar.testGetWheels(testCar.java:37)

        FAILURES!!!
        Tests run: 1,  Failures: 1,  Errors: 0       
       
注意:Time上的小點表示測試個數(shù),如果測試通過則顯示OK。否則在小點的后邊標(biāo)上F,表示該測試失敗。注意,在模擬出錯的測試中,我們會得到詳細的測試報告“expected:<4>; but was:<3>;”,這足以告訴我們問題發(fā)生在何處。下面就是你調(diào)試,測試,調(diào)試,測試...的過程,直至得到期望的結(jié)果。


Design by Contract(這句話我沒法翻譯)

Design by Contract本是Bertrand Meyer(Eiffel語言的創(chuàng)始人)開發(fā)的一種設(shè)計技術(shù)。我發(fā)現(xiàn)在JUnit中使用Design by Contract會帶來意想不到的效果。Design by Contract的核心是斷言(assersion)。斷言是一個布爾語句,該語句不能為假,如果為假,則表明出現(xiàn)了一個bug。Design by Contract使用三種斷言:前置條件(pre-conditions)、后置條件(post-conditions)和不變式(invariants)這里不打算詳細討論Design by Contract的細節(jié),而是希望其在測試中能發(fā)揮其作用。

前置條件在執(zhí)行測試之前可以用于判斷是否允許進入測試,即進入測試的條件。如 expectedWheels >; 0, myCar != null。后置條件用于在測試執(zhí)行后判斷測試的結(jié)果是否正確。如 expectedWheels==myCar.getWheels()。而不變式在判斷交易(Transaction)的一致性(consistency)方面尤為有用。我希望JUnit可以將Design by Contract作為未來版本的一個增強。


Refactoring(這句話我依然沒法翻譯)

Refactoring本來與測試沒有直接的聯(lián)系,而是與軟件熵有關(guān),但既然我們說測試能解決軟件熵問題,我們也就必須說出解決之道。(僅僅進行測試只能發(fā)現(xiàn)軟件熵,Refactoring則可解決軟件熵帶來的問題。)軟件熵引出了一個問題:是否需要重新設(shè)計整個軟件的結(jié)構(gòu)?理論上應(yīng)該如此,但現(xiàn)實不允許我們這么做。這或者是由于時間的原因,或者是由于費用的原因。重新設(shè)計整個軟件的結(jié)構(gòu)會給我們帶來短期的痛苦。而不停地給軟件打補丁甚至是補丁的補丁則會給我們帶來長期的痛苦。(不管怎樣,我們總處于水深火熱之中)

Refactoring是一個術(shù)語,用于描述一種技術(shù),利用這種技術(shù)我們可以免于重構(gòu)整個軟件所帶來的短期痛苦。當(dāng)你refactor時,你并不改變程序的功能,而是改變程序內(nèi)部的結(jié)構(gòu),使其更易理解和使用。如:該變一個方法的名字,將一個成員變量從一個類移到另一個類,將兩個類似方法抽象到父類中。所作的每一個步都很小,然而1-2個小時的Refactoring工作可以使你的程序結(jié)構(gòu)更適合目前的情況。Refactoring有一些規(guī)則:

1>; 不要在加入新功能的同時refactor已有的代碼。在這兩者間要有一個清晰的界限。如每天早上1-2個小時的Refactoring,其余時間添加新的功能。

2>; 在你開始Refactoring前,和Refactoring后都要保證測試能順利通過。否則Refactoring沒有任何意義。

3>; 進行小的Refactoring,大的就不是Refactoring了。如果你打算重構(gòu)整個軟件,就沒有必要Refactoring了。

只有在添加新功能和調(diào)試bug時才又必要Refactoring。不要等到交付軟件的最后關(guān)頭才Refactoring。那樣和打補丁的區(qū)別不大。Refactoring 用在回歸測試中也能顯示其威力。要明白,我不反對打補丁,但要記住打補丁是應(yīng)該最后使用的必殺絕招。(打補丁也需要很高的技術(shù),詳情參看微軟網(wǎng)站)


IDE對JUnit的支持

目前支持JUnit的Java IDE 包括 IDE 方式 個人評價(1-5,滿分5)
Forte for Java 3.0 Enterprise Edition plug-in 3
JBuilder 6 Enterprise Edition integrated with IDE 4
Visual Age for Java  support N/A

在IDE中如何使用JUnit,是非常具體的事情。不同的IDE有不同的使用方法。一旦理解了JUnit的本質(zhì),使用起來就十分容易了。所以我們不依賴于具體的IDE,而是集中精力講述如何利用JUnit編寫單元測試代碼。心急的人可參看資料。


JUnit簡介

既然我們已經(jīng)對JUnit有了一個大致的了解,我希望能給大家提供一個稍微正式一些的編寫JUnit測試文檔的手冊,明白其中的一些關(guān)鍵術(shù)語和概念。但我要聲明的是這并不是一本完全的手冊,只能認為是一本入門手冊。同其他OpenSource的軟件有同樣的問題,JUnit的文檔并沒有商業(yè)軟件文檔的那種有規(guī)則,簡潔和完全。由開發(fā)人員編寫的文檔總是說不太清楚問題,全整的文檔需要參考"官方"指南,API手冊,郵件討論組的郵件,甚至包括源代碼中及相關(guān)的注釋。

事實上問題并沒有那么復(fù)雜,除非你有非常特別的要求,否則,只需參考本文你就可以得到所需的大部分信息。


安裝

首先你要獲取JUnit的軟件包,從JUnit下載最新的軟件包(截至寫作本文時,JUnit的最新版本是3.7)。將其在適當(dāng)?shù)哪夸浵陆獍。這樣在安裝目錄(也就是你所選擇的解包的目錄)下你找到一個名為junit.jar的文件。將這個jar文件加入你的CLASSPATH系統(tǒng)變量。(IDE的設(shè)置會有所不同,參看你所喜愛的IDE的配置指南)JUnit就安裝完了。太easy了!

你一旦安裝完JUnit,就有可能想試試我們的Car和testCar類,沒問題,我已經(jīng)運行過了,你得到的結(jié)果應(yīng)該和我列出的結(jié)果類似。(以防新版JUnit使我的文章過時)

接下來,你可能會先寫測試代碼,再寫工作代碼,或者相反,先寫工作代碼,再寫測試代碼。我更贊成使用前一種方法:先寫測試代碼,再寫工作代碼。因為這樣可以使我們編寫工作代碼時清晰地了解工作類的行為。

要注意編寫一定能通過的測試代碼(如文中的例子)并沒有任何意義,只有測試代碼能幫助我們發(fā)現(xiàn)bug,測試代碼才有其價值。此外測試代碼還應(yīng)該對工作代碼進行全面的測試。如給方法調(diào)用的參數(shù)傳入空值、錯誤值和正確的值,看看方法的行為是否如你所期望的那樣。

你現(xiàn)在已經(jīng)知道了編寫測試類的基本步驟:
1>;擴展TestCase類;
2>;覆蓋runTest()方法(可選);
3>;寫一些testXXXXX()方法;


Fixture

解下來的問題是,如果你要對一個或若干個的類執(zhí)行多個測試,該怎么辦?JUnit對此有特殊的解決辦法。

如果需要在一個或若干個的類執(zhí)行多個測試,這些類就成為了測試的context。在JUnit中被稱為Fixture(如testCar類中的 myCar 和 expectedWheels )。當(dāng)你編寫測試代碼時,你會發(fā)現(xiàn)你花費了很多時間配置/初始化相關(guān)測試的Fixture。將配置Fixture的代碼放入測試類的構(gòu)造方法中并不可取,因為我們要求執(zhí)行多個測試,我并不希望某個測試的結(jié)果意外地(如果這是你要求的,那就另當(dāng)別論了)影響其他測試的結(jié)果。通常若干個測試會使用相同的Fixture,而每個測試又各有自己需要改變的地方。

為此,JUnit提供了兩個方法,定義在TestCase類中。

                protected void setUp() throws java.lang.Exception
                protected void tearDown() throws java.lang.Exception
               
覆蓋setUp()方法,初始化所有測試的Fixture(你甚至可以在setUp中建立網(wǎng)絡(luò)連接),將每個測試略有不同的地方在testXXX()方法中進行配置。

覆蓋tearDown()(我總想起一首叫雨滴的吉他曲),釋放你在setUp()中分配的永久性資源,如數(shù)據(jù)庫連接。

當(dāng)JUnit執(zhí)行測試時,它在執(zhí)行每個testXXXXX()方法前都調(diào)用setUp(),而在執(zhí)行每個testXXXXX()方法后都調(diào)用tearDown()方法,由此保證了測試不會相互影響。


TestCase

需要提醒一下,在junit.framework.Assert類中定義了相當(dāng)多的assert方法,主要有assert(), assert(), assertEquals(), assertNull(), assertSame(), assertTrue(), fail()等方法。如果你需要比較自己定義的類,如Car。assert方法需要你覆蓋Object類的equals()方法,以比較兩個對象的不同。實踐表明:如果你覆蓋了Object類的equals()方法,最好也覆蓋Object類的hashCode()方法。再進一步,連帶Object類的toString()方法也一并覆蓋。這樣可以使測試結(jié)果更具可讀性。

當(dāng)你設(shè)置好了Fixture后,下一步是編寫所需的testXXX()方法。一定要保證testXXX()方法的public屬性,否則無法通過內(nèi)省(reflection)對該測試進行調(diào)用。

每個擴展的TestCase類(也就是你編寫的測試類)會有多個testXXX()方法。一個testXXX()方法就是一個測試。要想運行這個測試,你必須定義如何運行該測試。如果你有多個testXXX()方法,你就要定義多次。JUnit支持兩種運行單個測試的方法:靜態(tài)的和動態(tài)的方法。

靜態(tài)的方法就是覆蓋TestCase類的runTest()方法,一般是采用內(nèi)部類的方式創(chuàng)建一個測試實例:
                TestCase test01 = new testCar("test getWheels" {
                        public void runTest() {
                                testGetWheels();
                        }
                }       
               
采用靜態(tài)的方法要注意要給每個測試一個名字(這個名字可以任意起,但你肯定希望這個名字有某種意義),這樣你就可以區(qū)分那個測試失敗了。

動態(tài)的方法是用內(nèi)省來實現(xiàn)runTest()以創(chuàng)建一個測試實例。這要求測試的名字就是需要調(diào)用的測試方法的名字:
                TestCase test01 = new testCar("testGetWheels";       
               
JUnit會動態(tài)查找并調(diào)用指定的測試方法。動態(tài)的方法很簡潔,但如果你鍵入了錯誤的名字就會得到一個令人奇怪的NoSuchMethodException異常。動態(tài)的方法和靜態(tài)的方法都很好,你可以按照自己的喜好來選擇。(先別著急選擇,后面還有一種更酷的方法等著你呢。)


TestSuite

一旦你創(chuàng)建了一些測試實例,下一步就是要讓他們能一起運行。我們必須定義一個TestSuite。在JUnit中,這就要求你在TestCase類中定義一個靜態(tài)的suite()方法。suite()方法就像main()方法一樣,JUnit用它來執(zhí)行測試。在suite()方法中,你將測試實例加到一個TestSuite對象中,并返回這個TestSuite對象。一個TestSuite對象可以運行一組測試。TestSuite和TestCase都實現(xiàn)了Test接口(interface),而Test接口定義了運行測試所需的方法。這就允許你用TestCase和TestSuite的組合創(chuàng)建一個TestSuite。這就是為什么我們前面說TestCase,TestSuite以及TestSuite組成了一個composite Pattern的原因。例子如下:
                public static Test suite() {
                        TestSuite suite= new TestSuite();
                        suite.addTest(new testCar("testGetWheels");
                        suite.addTest(new testCar("testGetSeats");
                        return suite;
                }       
               
從JUnit 2.0開始,有一種更簡單的動態(tài)定義測試實例的方法。你只需將類傳遞給TestSuite,JUnit會根據(jù)測試方法名自動創(chuàng)建相應(yīng)的測試實例。所以你的測試方法最好取名為testXXX()。例子如下:
                public static Test suite() {
                        return new TestSuite(testCar.class);
                }       
               
從JUnit的設(shè)計我們可看出,JUnit不僅可用于單元測試,也可用于集成測試。關(guān)于如何用JUnit進行集成測試請參考相關(guān)資料。

為了兼容性的考慮,下面列出使用靜態(tài)方法的例子:
                public static Test suite() {
                        TestSuite suite= new TestSuite();
                        suite.addTest(
                                new testCar("getWheels" {
                                         protected void runTest() { testGetWheels(); }
                                }
                        );
       
                        suite.addTest(
                                new testCar("getSeats" {
                                         protected void runTest() { testGetSeats(); }
                                }
                        );
                        return suite;                       
                }       
               
TestRunner

有了TestSuite我們就可以運行這些測試了,JUnit提供了三種界面來運行測試
                [Text  UI] junit.textui.TestRunner
                [AWT   UI] junit.awtui.TestRunner
                [Swing UI] junit.swingui.TestRunner       
               
我們前面已經(jīng)看過文本界面了,下面讓我們來看一看圖形界面:



界面很簡單,鍵入類名-testCar;蛟趩覷I的時候鍵入類名:
                [Windows] d:>;java junit.swingui.TestRunner testCar
                   [Unix] % java junit.swingui.TestRunner testCar
               
從圖形UI可以更好的運行測試可查單測試結(jié)果。還有一個問題需要注意:如果JUnit報告了測試沒有成功,JUnit會區(qū)分失。╢ailures)和錯誤(errors)。失敗是一個期望的被assert方法檢查到的結(jié)果。而錯誤則是意外的問題引起的,如ArrayIndexOutOfBoundsException。

由于TestRunner十分簡單,界面也比較直觀,故不多介紹。朋友們可自行參考相關(guān)資料。


JUnit最佳實踐

Martin Fowler(又是這位高人)說過:“當(dāng)你試圖打印輸出一些信息或調(diào)試一個表達式時,寫一些測試代碼來替代那些傳統(tǒng)的方法!币婚_始,你會發(fā)現(xiàn)你總是要創(chuàng)建一些新的Fixture,而且測試似乎使你的編程速度慢了下來。然而不久之后,你會發(fā)現(xiàn)你重復(fù)使用相同的Fixture,而且新的測試通常只涉及添加一個新的測試方法。

你可能會寫許多測試代碼,但你很快就會發(fā)現(xiàn)你設(shè)想出的測試只有一小部分是真正有用的。你所需要的測試是那些會失敗的測試,即那些你認為不會失敗的測試,或你認為應(yīng)該失敗卻成功的測試。

我們前面提到過測試是一個不會中斷的過程。一旦你有了一個測試,你就要一直確保其正常工作,以檢驗?zāi)闼尤氲男碌墓ぷ鞔a。不要每隔幾天或最后才運行測試,每天你都應(yīng)該運行一下測試代碼。這種投資很小,但可以確保你得到可以信賴的工作代碼。你的返工率降低了,你會有更多的時間編寫工作代碼。

不要認為壓力大,就不寫測試代碼。相反編寫測試代碼會使你的壓力逐漸減輕,應(yīng)為通過編寫測試代碼,你對類的行為有了確切的認識。你會更快地編寫出有效率地工作代碼。下面是一些具體的編寫測試代碼的技巧或較好的實踐方法:

1. 不要用TestCase的構(gòu)造函數(shù)初始化Fixture,而要用setUp()和tearDown()方法。
2. 不要依賴或假定測試運行的順序,因為JUnit利用Vector保存測試方法。所以不同的平臺會按不同的順序從Vector中取出測試方法。
3. 避免編寫有副作用的TestCase。例如:如果隨后的測試依賴于某些特定的交易數(shù)據(jù),就不要提交交易數(shù)據(jù)。簡單的會滾就可以了。
4. 當(dāng)繼承一個測試類時,記得調(diào)用父類的setUp()和tearDown()方法。
5. 將測試代碼和工作代碼放在一起,一邊同步編譯和更新。(使用Ant中有支持junit的task.)
6. 測試類和測試方法應(yīng)該有一致的命名方案。如在工作類名前加上test從而形成測試類名。
7. 確保測試與時間無關(guān),不要依賴使用過期的數(shù)據(jù)進行測試。導(dǎo)致在隨后的維護過程中很難重現(xiàn)測試。
8. 如果你編寫的軟件面向國際市場,編寫測試時要考慮國際化的因素。不要僅用母語的Locale進行測試。
9. 盡可能地利用JUnit提供地assert/fail方法以及異常處理的方法,可以使代碼更為簡潔。
10.測試要盡可能地小,執(zhí)行速度快。

事實上,JUnit還可用于集成測試,但我并沒涉及到,原因有兩個:一是因為沒有單元測試,集成測試無從談起。我們接受測試地概念已經(jīng)很不容易了,如果再引入集成測試就會更困難。二是我比較懶,希望將集成測試的任務(wù)交給測試人員去做。在JUnit的網(wǎng)站上有一些相關(guān)的文章,有空大家可以翻一翻。


JUnit與J2EE

如果大家仔細考慮一下的話,就會發(fā)現(xiàn),JUnit有自己的局限性,比如對圖形界面的測試,對servlet/JSP以及EJB的測試我們都沒有舉相關(guān)的例子。實際上,JUnit對于GUI界面,servlet/JSP,JavaBean以及EJB都有辦法測試。關(guān)于GUI的測試比較復(fù)雜,適合用一整篇文章來介紹。這里就不多說了。

前面我們所做的測試實際上有一個隱含的環(huán)境,JVM我們的類需要這個JVM來執(zhí)行。而在J2EE框架中,servlet/JSP,EJB都要求有自己的運行環(huán)境:Web Container和EJB Container。所以,要想對servlet/JSP,EJB進行測試就需要將其部署在相應(yīng)的Container中才能進行測試。由于EJB不涉及UI的問題(除非EJB操作XML數(shù)據(jù),此時的測試代碼比較難寫,有可能需要你比較兩棵DOM樹是否含有相同的內(nèi)容)只要部署上去之后就可以運行測試代碼了。此時setUp()方法顯得特別有用,你可以在setUp()方法中利用JNDI查找特定的EJB。而在testXXX()方法中調(diào)用并測試這些EJB的方法。

這里所指的JavaBean同樣沒有UI的問題,比如,我們用JavaBean來訪問數(shù)據(jù)庫,或用JavaBean來包裹EJB。如果這類JavaBean沒有用到Container的提供的服務(wù),則可直接進行測試,同我們前面所說的一般的類的測試方法一樣。如果這類JavaBean用到了Container的提供的服務(wù),則需要將其部署在Container中才能進行測試。方法與EJB類似。

對于servlet/JSP的測試則比較棘手,有人建議在測試代碼中構(gòu)造HttpRequest和HttpResponse,然后進行比較,這就要求開發(fā)人員對HTTP協(xié)議以及servlet/JSP的內(nèi)部實現(xiàn)有比較深的認識。我認為這招不太現(xiàn)實。也有人提出使用HttpUnit。由于我對Cactus和HttpUnit 了解不多,所以無法做出合適的建議。希望各位先知們能不吝賜教。

正是由于JUnit的開放性和簡單易行,才會引出這篇介紹文章。但技術(shù)總在不斷地更新,而且我對測試并沒有非常深入的理解;我可以將一個復(fù)雜的概念簡化成一句非常容易理解的話。但我的本意只是希望能降低開發(fā)人員步入測試領(lǐng)域的門檻,而不是要修改或重新定義一些概念。這一點是特別要強調(diào)的。最后,如果有些兄弟姐妹能給我指出一些注意事項或我對某些問題的理解有誤,我會非常感激的。

論壇徽章:
0
2 [報告]
發(fā)表于 2003-12-08 18:26 |只看該作者

應(yīng)用JUnit實施單元測試

需要HttpUnit有關(guān)例程介紹!

論壇徽章:
0
3 [報告]
發(fā)表于 2004-02-20 14:55 |只看該作者

應(yīng)用JUnit實施單元測試

這篇文章幫了 我的大忙!

論壇徽章:
0
4 [報告]
發(fā)表于 2004-02-20 22:38 |只看該作者

應(yīng)用JUnit實施單元測試

我最近要用junit測試ejb,用jbuilder中自建的junit test client生成的代碼,接下來該怎么做呢?除了輸入測試值還要做什么呢?

論壇徽章:
0
5 [報告]
發(fā)表于 2006-04-10 10:59 |只看該作者
你說的我都明白!
可是我還是不會寫,我自己的這些測試.
我用你那種方法試過,可是不行,根本沒有提高測試率!
幫忙看一下好不?
在SwingMediator這個類中,他繼承 AbstractMediator這個類
public HelpFrame getHelpFrame() {
        return hf;
    }
那這個該怎么寫呢?

論壇徽章:
0
6 [報告]
發(fā)表于 2006-04-10 11:38 |只看該作者
忘了說,是用junit測試.

論壇徽章:
0
7 [報告]
發(fā)表于 2008-06-09 16:42 |只看該作者
很棒的文章,謝謝!正好用得上!

論壇徽章:
6
CU大;照
日期:2013-04-17 10:59:39CU大;照
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大;照
日期:2013-04-17 11:02:36CU大;照
日期:2013-04-17 11:02:582015年辭舊歲徽章
日期:2015-03-03 16:54:15
8 [報告]
發(fā)表于 2008-06-09 19:02 |只看該作者
真會翻,

論壇徽章:
0
9 [報告]
發(fā)表于 2008-06-09 21:09 |只看該作者
好是好,可是寫junit test耗時太厲害,每個class要有一個對應(yīng)的test class,每個method都要有一個test method,煩得不得了。

論壇徽章:
0
10 [報告]
發(fā)表于 2008-08-22 13:57 |只看該作者

對于熱心的自由軟件的幫助,支持

對于熱心的自由軟件的幫助,支持LZ的文檔!頂!
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP