什么是單元測(cè)試
工廠在組裝一臺(tái)電視機(jī)之前,會(huì)對(duì)每個(gè)元件都進(jìn)行測(cè)試,這,就是單元測(cè)試。
單元測(cè)試(模塊測(cè)試)是開(kāi)發(fā)者編寫(xiě)的一小段代碼,用于檢驗(yàn)被測(cè)代碼的一個(gè)很小的、很明確的功能是否正確。通常而言,一個(gè)單元測(cè)試是用于判斷某個(gè)特定條件(或者場(chǎng)景)下某個(gè)特定函數(shù)的行為。例如,你可能把一個(gè)很大的值放入一個(gè)有序list 中去,然后確認(rèn)該值出現(xiàn)在list 的尾部?;蛘撸憧赡軙?huì)從字符串中刪除匹配某種模式的字符,然后確認(rèn)字符串確實(shí)不再包含這些字符了。
單元測(cè)試是由程序員自己來(lái)完成,最終受益的也是程序員自己??梢赃@么說(shuō),程序員有責(zé)任編寫(xiě)功能代碼,同時(shí)也就有責(zé)任為自己的代碼編寫(xiě)單元測(cè)試。執(zhí)行單元測(cè)試,就是為了證明這段代碼的行為和我們期望的一致。
其實(shí)我們每天都在做單元測(cè)試。你寫(xiě)了一個(gè)函數(shù),除了極簡(jiǎn)單的外,總是要執(zhí)行一下,看看功能是否正常,有時(shí)還要想辦法輸出些數(shù)據(jù),如彈出信息窗口什么的,這,也是單元測(cè)試,把這種單元測(cè)試稱為臨時(shí)單元測(cè)試。只進(jìn)行了臨時(shí)單元測(cè)試的軟件,針對(duì)代碼的測(cè)試很不完整,代碼覆蓋率要超過(guò)70%都很困難,未覆蓋的代碼可能遺留大量的細(xì)小的錯(cuò)誤,這些錯(cuò)誤還會(huì)互相影響,當(dāng)BUG暴露出來(lái)的時(shí)候難于調(diào)試,大幅度提高后期測(cè)試和維護(hù)成本,也降低了開(kāi)發(fā)商的競(jìng)爭(zhēng)力??梢哉f(shuō),進(jìn)行充分的單元測(cè)試,是提高軟件質(zhì)量,降低開(kāi)發(fā)成本的必由之路。
對(duì)于程序員來(lái)說(shuō),如果養(yǎng)成了對(duì)自己寫(xiě)的代碼進(jìn)行單元測(cè)試的習(xí)慣,不但可以寫(xiě)出高質(zhì)量的代碼,而且還能提高編程水平。
要進(jìn)行充分的單元測(cè)試,應(yīng)專門(mén)編寫(xiě)測(cè)試代碼,并與產(chǎn)品代碼隔離。我認(rèn)為,比較簡(jiǎn)單的辦法是為產(chǎn)品工程建立對(duì)應(yīng)的測(cè)試工程,為每個(gè)類建立對(duì)應(yīng)的測(cè)試類,為每個(gè)函數(shù)(很簡(jiǎn)單的除外)建立測(cè)試函數(shù)。首先就幾個(gè)概念談?wù)勎业目捶ā?/p>
一般認(rèn)為,在結(jié)構(gòu)化程序時(shí)代,單元測(cè)試所說(shuō)的單元是指函數(shù),在當(dāng)今的面向?qū)ο髸r(shí)代,單元測(cè)試所說(shuō)的單元是指類。以我的實(shí)踐來(lái)看,以類作為測(cè)試單位,復(fù)雜度高,可操作性較差,因此仍然主張以函數(shù)作為單元測(cè)試的測(cè)試單位,但可以用一個(gè)測(cè)試類來(lái)組織某個(gè)類的所有測(cè)試函數(shù)。單元測(cè)試不應(yīng)過(guò)分強(qiáng)調(diào)面向?qū)ο?,因?yàn)榫植看a依然是結(jié)構(gòu)化的。單元測(cè)試的工作量較大,簡(jiǎn)單實(shí)用高效才是硬道理。
有一種看法是,只測(cè)試類的接口(公有函數(shù)),不測(cè)試其他函數(shù),從面向?qū)ο蠼嵌葋?lái)看,確實(shí)有其道理,但是,測(cè)試的目的是找錯(cuò)并最終排錯(cuò),因此,只要是包含錯(cuò)誤的可能性較大的函數(shù)都要測(cè)試,跟函數(shù)是否私有沒(méi)有關(guān)系。對(duì)于C++來(lái)說(shuō),可以用一種簡(jiǎn)單的方法區(qū)隔需測(cè)試的函數(shù):簡(jiǎn)單的函數(shù)如數(shù)據(jù)讀寫(xiě)函數(shù)的實(shí)現(xiàn)在頭文件中編寫(xiě)(inline函數(shù)),所有在源文件編寫(xiě)實(shí)現(xiàn)的函數(shù)都要進(jìn)行測(cè)試(構(gòu)造函數(shù)和析構(gòu)函數(shù)除外)。
單元測(cè)試之測(cè)試目的
首先保證代碼質(zhì)量。
其次保證代碼的可維護(hù)。
再此保證代碼的可擴(kuò)展。
目的之一代碼的代碼質(zhì)量。
我們編寫(xiě)的代碼雖然可以通過(guò)編譯器檢測(cè)到語(yǔ)法的正確性質(zhì),但并不能保證代碼邏輯也是正確的。我們?cè)撛趺幢WC代碼執(zhí)行是正確的呢。好下面我們來(lái)看下代碼。
java 代碼
int add(int x, int y){
return x+y;
}
上面的功能模塊。下面是段測(cè)試代碼
java 代碼
void testAdd(){
//我們要求程序邏輯是1+4=5;
assertEquals(5,add(1,4);
}
經(jīng)過(guò)測(cè)試以后,如果你修改了int add(int x, int y);里面的邏輯,如果修改的正確,測(cè)試代碼始終都是見(jiàn)到綠色的。如果你邏輯錯(cuò)了。那不好意思,你的測(cè)試將會(huì)讓你重新寫(xiě)那段邏輯代碼。直到你正確為止。
有個(gè)比較特殊的情況,如果我測(cè)試代碼寫(xiě)成這樣,那我保證邏輯代碼的正確性,但我卻看不到我期待的綠色,這有是什么原因呢?
java 代碼
void testAdd(){
//我們要求程序邏輯是1+4=5;
assertEquals(6,add(1,4);
}
我個(gè)人認(rèn)為這個(gè)問(wèn)題并是邏輯代碼的問(wèn)題,而是你測(cè)試代碼中的邏輯問(wèn)題,噢,MyGot,作為程序員的我。已經(jīng)為邏輯代碼傷腦筋了。還要為測(cè)試代碼煩惱,做人真命苦啊。 想來(lái)也確實(shí)是這樣。
這就引申了另外一個(gè)問(wèn)題,怎么樣才可以保證我邏輯代碼的可測(cè)性?
目的之二代碼的可維護(hù)性。
就拿上面的例子來(lái)說(shuō)吧。只要我們的單元測(cè)試是正確的,那我們就可以保證無(wú)論你怎么修改那段代碼,只要測(cè)試代碼可以產(chǎn)生綠色條,那OK,你修改的邏輯代碼是正確的。當(dāng)然可維護(hù)并非只有這點(diǎn),還有,比如保證修改了這段代碼不會(huì)影響到其他的模塊等。
目的之三代碼的可擴(kuò)展。
對(duì)于這點(diǎn)我理解很膚淺。只能表達(dá)表面的東西,希望。
對(duì)于可擴(kuò)展我覺(jué)得保遵循一個(gè)代碼之間的耦合度降到最低。就OK了。單元測(cè)試對(duì)這方面有很強(qiáng)的好處,為了程序的可維護(hù)性,它可以強(qiáng)迫你寫(xiě)低耦合度的程序。
單元測(cè)試的優(yōu)點(diǎn)
1、它是一種驗(yàn)證行為。
程序中的每一項(xiàng)功能都是測(cè)試來(lái)驗(yàn)證它的正確性。它為以后的開(kāi)發(fā)提供支緩。就算是開(kāi)發(fā)后期,我們也可以輕松的增加功能或更改程序結(jié)構(gòu),而不用擔(dān)心這個(gè)過(guò)程中會(huì)破壞重要的東西。而且它為代碼的重構(gòu)提供了保障。這樣,我們就可以更自由的對(duì)程序進(jìn)行改進(jìn)。
2、它是一種設(shè)計(jì)行為。
編寫(xiě)單元測(cè)試將使我們從調(diào)用者觀察、思考。特別是先寫(xiě)測(cè)試(test-first),迫使我們把程序設(shè)計(jì)
成易于調(diào)用和可測(cè)試的,即迫使我們解除軟件中的耦合。
3、它是一種編寫(xiě)文檔的行為。
單元測(cè)試是一種無(wú)價(jià)的文檔,它是展示函數(shù)或類如何使用的最佳文檔。這份文檔是可編譯、可運(yùn)行的,并且它保持最新,永遠(yuǎn)與代碼同步。
4、它具有回歸性。
自動(dòng)化的單元測(cè)試避免了代碼出現(xiàn)回歸,編寫(xiě)完成之后,可以隨時(shí)隨地的快速運(yùn)行測(cè)試。
單元測(cè)試的范疇
如果要給單元測(cè)試定義一個(gè)明確的范疇,指出哪些功能是屬于單元測(cè)試,這似乎很難。但下面討論的四個(gè)問(wèn)題,基本上可以說(shuō)明單元測(cè)試的范疇,單元測(cè)試所要做的工作。
1、 它的行為和我期望的一致嗎?
這是單元測(cè)試最根本的目的,我們就是用單元測(cè)試的代碼來(lái)證明它所做的就是我們所期望的。
2、 它的行為一直和我期望的一致嗎?
編寫(xiě)單元測(cè)試,如果只測(cè)試代碼的一條正確路徑,讓它正確走一遍,并不算是真正的完成。軟件開(kāi)發(fā)是一個(gè)項(xiàng)復(fù)雜的工程,在測(cè)試某段代碼的行為是否和你的期望一 致時(shí),你需要確認(rèn):在任何情況下,這段代碼是否都和你的期望一致;譬如參數(shù)很可疑、硬盤(pán)沒(méi)有剩余空間、緩沖區(qū)溢出、網(wǎng)絡(luò)掉線的時(shí)候。
3、 我可以依賴單元測(cè)試嗎?
不能依賴的代碼是沒(méi)有多大用處的。既然單元測(cè)試是用來(lái)保證代碼的正確性,那么單元測(cè)試也一定要值得依賴。
4、 單元測(cè)試說(shuō)明我的意圖了嗎?
單元測(cè)試能夠幫我們充分了解代碼的用法,從效果上而言,單元測(cè)試就像是能執(zhí)行的文檔,說(shuō)明了在你用各種條件調(diào)用代碼時(shí),你所能期望這段代碼完成的功能。
評(píng)論