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

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

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

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

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

             }

           };

這個(gè)測(cè)試用例的意圖很明顯,是對(duì)MyComplex類進(jìn)行相等測(cè)試,根據(jù)復(fù)數(shù)的數(shù)學(xué)知識(shí),能夠得到note:1處我們期望的是相等,而note:2處則是不等。有了這個(gè)測(cè)試用例后,對(duì)其進(jìn)行編譯,由于MyComplex類沒有進(jìn)行定義,因此將無法通過編譯,不過,這是單元測(cè)試中必然會(huì)遇到的問題。對(duì)于無法編譯的恐懼驅(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)在編譯沒問題了,可以松一口氣了,不過無法通過測(cè)試,于是再接再厲,寫下:

           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.

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

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

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