您的位置:軟件測(cè)試 > 開源軟件測(cè)試 > 開源單元測(cè)試工具 > junit
應(yīng)用JUnit實(shí)施單元測(cè)試
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時(shí)間:[ 2013/3/25 15:08:32 ] 推薦標(biāo)簽:

改版后的testCar已經(jīng)面目全非。先讓我們了解這些改動(dòng)都是什么含義,再看如何執(zhí)行這個(gè)測(cè)試。

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

2>;繼承 TestCase ?梢詴簳r(shí)將一個(gè)TestCase看作是對(duì)某個(gè)類進(jìn)行測(cè)試的方法的集合。詳細(xì)介紹請(qǐng)參看JUnit資料

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

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

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

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

如何運(yùn)行該測(cè)試呢?手工的方法是鍵入如下命令:

[Windows] d:>;java junit.textui.TestRunner testCar
   [Unix] % java junit.textui.TestRunner testCar

別擔(dān)心你要敲的字符量,以后在IDE中,只要點(diǎn)幾下鼠標(biāo)成了。運(yùn)行結(jié)果應(yīng)該如下所示,表明執(zhí)行了一個(gè)測(cè)試,并通過了測(cè)試:

.
Time: 0

OK (1 tests)

如果我們將Car.getWheels()中返回的的值修改為3,模擬出錯(cuò)的情形,則會(huì)得到如下結(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上的小點(diǎn)表示測(cè)試個(gè)數(shù),如果測(cè)試通過則顯示OK。否則在小點(diǎn)的后邊標(biāo)上F,表示該測(cè)試失敗。注意,在模擬出錯(cuò)的測(cè)試中,我們會(huì)得到詳細(xì)的測(cè)試報(bào)告“expected:<4>; but was:<3>;”,這足以告訴我們問題發(fā)生在何處。下面是你調(diào)試,測(cè)試,調(diào)試,測(cè)試...的過程,直至得到期望的結(jié)果。


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

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

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


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

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

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

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

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

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

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


IDE對(duì)JUnit的支持

目前支持JUnit的Java IDE 包括 IDE 方式 個(gè)人評(píng)價(jià)(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編寫單元測(cè)試代碼。心急的人可參看資料。


JUnit簡(jiǎn)介

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

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


安裝

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

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

接下來,你可能會(huì)先寫測(cè)試代碼,再寫工作代碼,或者相反,先寫工作代碼,再寫測(cè)試代碼。我更贊成使用前一種方法:先寫測(cè)試代碼,再寫工作代碼。因?yàn)檫@樣可以使我們編寫工作代碼時(shí)清晰地了解工作類的行為。

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

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


Fixture

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

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

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

protected void setUp() throws java.lang.Exception
protected void tearDown() throws java.lang.Exception

覆蓋setUp()方法,初始化所有測(cè)試的Fixture(你甚至可以在setUp中建立網(wǎng)絡(luò)連接),將每個(gè)測(cè)試略有不同的地方在testXXX()方法中進(jìn)行配置。

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

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

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