您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 > cppUnit
測試驅(qū)動開發(fā)方法介紹及CPPUnit使用指南
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時間:[ 2013/1/25 16:07:11 ] 推薦標(biāo)簽:

 單元測試(Unit Test)是一種測試方法,用于對類,方法等進(jìn)行行為驗證。舉一個簡單的例子:如果需要測試一個累加函數(shù)int sum(int k),單元測試表現(xiàn)為給此函數(shù)不同的輸入,然后驗證對應(yīng)的輸出是否滿足要求。如對sum(int k),給他一些輸入,這些輸入應(yīng)該滿足人腦稀奇古怪的念頭,可以是sum(0);sum(5);sum(-5);sum(100000);sum(5.1234);對于這些輸入電腦有可能糊涂,但是人腦不能,他要給出在每種輸入后的預(yù)期結(jié)果,然后與函數(shù)輸出進(jìn)行比較,以確定函數(shù)運(yùn)行在預(yù)期范圍內(nèi)。這是一個單元測試,簡單,明了。

       單元測試長期以來一直被打入軟件開發(fā)的冷宮,究其原因,大概是意識形態(tài)的問題。如果詢問開發(fā)人員:為什么不采用單元測試?得到的回答十有八九是這種模式:寫代碼時間都不夠更何況去做測試了。(我原先也是屬于那八九中的一個)但是,有一個結(jié)論:寫單元測試可以節(jié)省開發(fā)時間。這也許令人匪夷所思,但是,經(jīng)過切身體會,確實如此,不過有一個前提:在編碼前寫測試。很有些反其道而行之的韻味。當(dāng)年在俠客島上,眾多中原俠客參悟“俠客行”無果,而不識字的少年卻窺探到武學(xué)精髓。很多事情往往是這樣的,按常理行不通,換個方向則行云流水。且說要編寫的代碼,好比少林寺的武僧,在下山行俠之前要經(jīng)過少林銅人陣的考驗。眾多武僧在銅人陣中因為一招稀奇古怪的招式敗下陣來比比皆是。如何才能通過銅人陣的考驗?zāi)?如果從修行的開始了解銅人陣,并在修行中不斷的接受銅人們的折磨,那么后的通過將不成問題。本著以上的指導(dǎo)思想,在編寫代碼前先設(shè)計測試用例,之后再編寫代碼,這么做的好處是:從一開始明白代碼的目的是什么,對于代碼將會受到的折磨了然于胸,用術(shù)語說是:需求明確,代碼覆蓋率高。我的切身體會是在使用這種方法后犯低級錯誤的概率減小了,幾乎不會使用單步測試,F(xiàn)在算是對Kent Beck大師所描述的那種十分鐘不做單元測試都會覺得心驚肉跳的心情有所體會了。還有一個好處,是復(fù)用程度的提高。這個好處的論證有點詭辯的味道,首先,編寫出來的代碼本身有一個用戶,那是我們需要實現(xiàn)的軟件中的代碼,另外一個用戶則來自于測試用例,因此,這樣的代碼本身的重用性較強(qiáng)。這點也不得不承認(rèn),在編寫代測試用例的時候,將會不自覺地考慮到在軟件中的嵌入,因此,這種情況下作出的設(shè)計會有較低的耦合性。將測試驅(qū)動與經(jīng)典的先代碼后測試進(jìn)行比較,很重要的一個將是面臨的心境的不同。寫好的代碼是自己的血肉,沒有人會希望它脆弱,也不愿意看到它的失敗,因此,在測試的時候,往往擔(dān)驚受怕,手指在回車鍵上方盤旋,繃緊的神經(jīng)頻頻接受考驗。而對于測試驅(qū)動來說,出生于艱苦的環(huán)境,每天努力打拼,為的是能夠出人頭地,成長為健壯的代碼,因此我們會毫不猶豫的按下回車鍵,讓暴風(fēng)雨來得更猛烈些吧!

       在進(jìn)行測試驅(qū)動的過程中,有一點是很重要的,那是保持它的旋律。好比一出精彩的電影,有黯然神傷的低谷,也有激情澎湃的高潮。測試驅(qū)動開發(fā)的旋律是:設(shè)計測試用例,編寫少的代碼通過測試,重構(gòu)代碼,設(shè)計下一個測試用例。其中,在編寫代碼通過測試及重構(gòu)代碼的過程往往需要幾個迭代過程,期間跌宕起伏,精彩刺激。在設(shè)計好測試用例后,對其進(jìn)行編譯,這時將會遭遇到第一個低谷:編譯錯誤。我們的努力目標(biāo)是通過編譯,這時候,我們編寫少的代碼通過編譯,這樣迎來了第一個上升期,但是又將面臨則測試無法通過的問題,于是再接再厲,增加代碼的功能,這樣,我們通過了測試,也迎來了第一個高潮。美好的事情總是需要變得更美好,于是我們著手對代碼進(jìn)行修整,使它更優(yōu)雅,我們不允許任何的重復(fù),copy&paste是我們的死敵,不允許看不懂的代碼,那是理解的障礙,不允許任何不新鮮的味道從代碼中飄出。重構(gòu)將幫助我們達(dá)到盡善盡美,而這一切的代價僅僅是幾分鐘的時間。但是,不要操之過急,否則會燙壞舌頭的。一步一步的進(jìn)行,每次的修改都要保證之前通過的測試,這樣,我們終將穩(wěn)步的達(dá)到幸福的彼岸!

人都是有惰性的,惰性常常與失敗,錯誤聯(lián)系在一起。但是,惰性也代來了很多的好處。又是一個反其道而行之的例子。在使用測試驅(qū)動的過程中,如果每次進(jìn)行測試都需要組織測試的環(huán)境及輸出格式,并且比較屏幕上飛出來的數(shù)據(jù),那么,再勤勞的人也無法堅持這項工作,測試驅(qū)動也將成為一個美麗的空中樓閣。要充分發(fā)揮測試驅(qū)動的威力,必須具備以下“必要非充分”條件:能夠方便建立測試環(huán)境;有良好的輸出形式;可以方便的比較測試結(jié)果。有了以上條件后,人們可以在彈指間建立測試環(huán)境,進(jìn)行頻繁的測試,讓自己的代碼在出山前接受頻繁的考驗。JUnit是Kent Beck大師建立起的一套JAVA環(huán)境下的單元測試框架。它能夠滿足上述測試驅(qū)動的必要條件,提供了方便的測試環(huán)境,良好的屏幕輸出以及結(jié)果比對機(jī)制。雖然JUnit是JAVA的,但是測試驅(qū)動卻是所有開發(fā)者的。對于行走于CPP世界的人們,CPPUnit可以滿足他們的要求。    CPPUnit是Michael Feathers建立一個開放源碼的單元測試庫,是JUnit的C++版本,同樣提供了便利的條件。它的老巢位于http://sourceforge.net/projects/cppunit/。在將CPPUnit應(yīng)用于測試驅(qū)動開發(fā)之前,首先要明了幾個概念:CPPUnit按照層次管理測試。底層的是Test Case,這里是測試代碼存在的地方,換句話說,是測試函數(shù)。當(dāng)有了幾個Test Case以后,可以把他們組織成Test Fixture。在Test Fixture中,可以建立被測試的類的實例,并編寫Test Case對類實例進(jìn)行測試。當(dāng)有了多個Test Fixture后可以使用Test Suite來對測試進(jìn)行管理。借用CPPUnit上的例子,需要設(shè)計一個復(fù)數(shù)類,首先希望復(fù)數(shù)類能夠使用“==”進(jìn)行判斷,因此,先構(gòu)思一個Test Case:

           class ComplexNumberTest : public CppUnit::TestCase {

           public:

             ComplexNumberTest( std::string name ) : CppUnit::TestCase( name ) {}

           

             void runTest() {

               CPPUNIT_ASSERT( MyComplex (10, 1) == MyComplex (10, 1) ); // note:1

               CPPUNIT_ASSERT( !(MyComplex (1, 1) == MyComplex (2, 2)) ); //note:2

             }

           };

這個測試用例的意圖很明顯,是對MyComplex類進(jìn)行相等測試,根據(jù)復(fù)數(shù)的數(shù)學(xué)知識,能夠得到note:1處我們期望的是相等,而note:2處則是不等。有了這個測試用例后,對其進(jìn)行編譯,由于MyComplex類沒有進(jìn)行定義,因此將無法通過編譯,不過,這是單元測試中必然會遇到的問題。對于無法編譯的恐懼驅(qū)使我們盡快的完成下面的代碼:

           //If we compile now ,we get compile error.So keep fixing it.

           bool operator==( const MyComplex &a, const MyComplex &b)

           {

             return true;

           }

           //Now compile it again,Ok!Run it,we'll get some fail.

           //This is because the operator==() doesn't work properly.Keep fixing it.

現(xiàn)在編譯沒問題了,可以松一口氣了,不過無法通過測試,于是再接再厲,寫下:

           class MyComplex {

             friend bool operator ==(const MyComplex& a, const MyComplex& b);

             double real, imaginary;

           public:

             MyComplex( double r, double i = 0 )

               : real(r)

                   , imaginary(i)

             {

             }

           };

         

           bool operator ==( const MyComplex &a, const MyComplex &b )

           {

             return a.real == b.real  &&  a.imaginary == b.imaginary;

           }

           //If we compile now and run our test it will pass.

編譯,測試,通過了,這個世界清靜了,恍如來到了桃花源…

不過,我們要的盡善盡美,MyComplex不夠美麗,于是改了個名字CComplex,這下大功告成,但是,心里始終還是有個結(jié),如何把它用在自己的項目中呢?欲知后事,請代下回分解。

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