單元測(cè)試經(jīng)驗(yàn)總結(jié)
1. 概述
工廠(chǎng)在組裝一臺(tái)電視機(jī)之前,會(huì)對(duì)每個(gè)元件都進(jìn)行測(cè)試,這,就是單元測(cè)試。其實(shí)我們每天都在做單元測(cè)試。你寫(xiě)了一個(gè)函數(shù),除了極簡(jiǎn)單的外,總是要執(zhí)行一下,看看功能是否正常,有時(shí)還要想辦法輸出些數(shù)據(jù),如彈出信息窗口什么的,這,也是單元測(cè)試,我們把這種單元測(cè)試稱(chēng)為臨時(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)力。可以說(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)專(zhuān)門(mén)編寫(xiě)測(cè)試代碼,并與產(chǎn)品代碼隔離。我們認(rèn)為,比較簡(jiǎn)單的辦法是為產(chǎn)品工程建立對(duì)應(yīng)的測(cè)試工程,為每個(gè)類(lèi)建立對(duì)應(yīng)的測(cè)試類(lèi),為每個(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ō)的單元是指類(lèi)。以我們的實(shí)踐來(lái)看,以類(lèi)作為測(cè)試單位,復(fù)雜度高,可操作性較差,因此仍然主張以函數(shù)作為單元測(cè)試的測(cè)試單位,但可以用一個(gè)測(cè)試類(lèi)來(lái)組織某個(gè)類(lèi)的所有測(cè)試函數(shù)。單元測(cè)試不應(yīng)過(guò)分強(qiáng)調(diào)面向?qū)ο螅驗(yàn)榫植看a依然是結(jié)構(gòu)化的。單元測(cè)試的工作量較大,簡(jiǎn)單實(shí)用高效才是硬道理。
有一種看法是,只測(cè)試類(lèi)的接口(公有函數(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ù)除外)。
2.什么時(shí)間開(kāi)始測(cè)試
什么時(shí)候測(cè)試?單元測(cè)試越早越好,早到什么程度?XP開(kāi)發(fā)理論講究TDD,即測(cè)試驅(qū)動(dòng)開(kāi)發(fā),先編寫(xiě)測(cè)試代碼,再進(jìn)行開(kāi)發(fā)。在實(shí)際的工作中,可以不必過(guò)分強(qiáng)調(diào)先什么后什么,重要的是高效和感覺(jué)舒適。從我們的經(jīng)驗(yàn)來(lái)看,先編寫(xiě)產(chǎn)品函數(shù)的框架,然后編寫(xiě)測(cè)試函數(shù),針對(duì)產(chǎn)品函數(shù)的功能編寫(xiě)測(cè)試用例,然后編寫(xiě)產(chǎn)品函數(shù)的代碼,每寫(xiě)一個(gè)功能點(diǎn)都運(yùn)行測(cè)試,隨時(shí)補(bǔ)充測(cè)試用例。所謂先編寫(xiě)產(chǎn)品函數(shù)的框架,是指先編寫(xiě)函數(shù)空的實(shí)現(xiàn),有返回值的隨便返回一個(gè)值,編譯通過(guò)后再編寫(xiě)測(cè)試代碼,這時(shí),函數(shù)名、參數(shù)表、返回類(lèi)型都應(yīng)該確定下來(lái)了,所編寫(xiě)的測(cè)試代碼以后需修改的可能性比較小。
3.誰(shuí)來(lái)測(cè)試
由誰(shuí)測(cè)試?單元測(cè)試與其他測(cè)試不同,單元測(cè)試可看作是編碼工作的一部分,應(yīng)該由程序員完成,也就是說(shuō),經(jīng)過(guò)了單元測(cè)試的代碼才是已完成的代碼,提交產(chǎn)品代碼時(shí)也要同時(shí)提交測(cè)試代碼。測(cè)試部門(mén)可以作一定程度的審核。
4.關(guān)于樁代碼
我們認(rèn)為,單元測(cè)試應(yīng)避免編寫(xiě)樁代碼。樁代碼就是用來(lái)代替某些代碼的代碼,例如,產(chǎn)品函數(shù)或測(cè)試函數(shù)調(diào)用了一個(gè)未編寫(xiě)的函數(shù),可以編寫(xiě)樁函數(shù)來(lái)代替該被調(diào)用的函數(shù),樁代碼也用于實(shí)現(xiàn)測(cè)試隔離。采用由底向上的方式進(jìn)行開(kāi)發(fā),底層的代碼先開(kāi)發(fā)并先測(cè)試,可以避免編寫(xiě)樁代碼,這樣做的好處有:減少了工作量;測(cè)試上層函數(shù)時(shí),也是對(duì)下層函數(shù)的間接測(cè)試;當(dāng)下層函數(shù)修改時(shí),通過(guò)回歸測(cè)試可以確認(rèn)修改是否導(dǎo)致上層函數(shù)產(chǎn)生錯(cuò)誤。
單元測(cè)試的基本策略
1.概述
當(dāng)設(shè)計(jì)一個(gè)單元測(cè)試的策略時(shí),可以采用三種基本的組織方法。它們分別是自上而下法、自下而上法和分離法。在接下來(lái)的第二、第三和第四部分將對(duì)上述三種方法的詳細(xì)內(nèi)容、各自的優(yōu)點(diǎn)和缺點(diǎn)分別進(jìn)行介紹。在文章中要一直用到測(cè)試驅(qū)動(dòng)和樁模塊這兩個(gè)概念。所謂的測(cè)試驅(qū)動(dòng)是指能使軟件執(zhí)行的軟件,它的目的就是為了測(cè)試軟件,提供一個(gè)能設(shè)置輸入?yún)?shù)的框架,并執(zhí)行這個(gè)框架單元以得到相應(yīng)的輸出參數(shù)。而樁模塊是指一個(gè)模擬單元,用這個(gè)模擬單元來(lái)替代真實(shí)的單元完成測(cè)試。
2. 自上而下法 2.1 詳述
在自上而下的測(cè)試過(guò)程中,每個(gè)單元是通過(guò)使用它們來(lái)進(jìn)行測(cè)試的,這個(gè)過(guò)程是由調(diào)用這些被測(cè)單元的其他獨(dú)立的單元完成的。
首先測(cè)試最高層的單元,將所有的調(diào)用單元用樁模塊替換。接著用實(shí)際的調(diào)用單元替換樁模塊,而繼續(xù)將較低層次的單元用樁模塊替換。重復(fù)這個(gè)過(guò)程直到測(cè)試了最底層的單元。自上而下測(cè)試法需要測(cè)試樁,而不需要測(cè)試驅(qū)動(dòng)。
圖2.1描述了使用測(cè)試樁和一些已測(cè)試單元來(lái)測(cè)試單元D的過(guò)程,假設(shè)單元A,B,C已經(jīng)用自上而下法進(jìn)行了測(cè)試。
由圖2.1得到的是一個(gè)使用基于自上而下組織方法的單元測(cè)試計(jì)劃,其過(guò)程可以描述如下:
1) 步驟1:測(cè)試A單元,使用B,C,D單元的樁模塊。
2) 步驟2:測(cè)試B單元,通過(guò)已測(cè)試過(guò)的A單元來(lái)調(diào)用它,并且使用C,D單元的樁
模塊。步驟3:測(cè)試C單元,通過(guò)已測(cè)試過(guò)的A單元來(lái)調(diào)用它,并且使用已通過(guò)測(cè)試的B單元和D單元的樁模塊。
3) 步驟4:測(cè)試D單元,從已測(cè)試過(guò)的A單元調(diào)用它,使用已測(cè)試過(guò)的B和C單元,
并且將E,F(xiàn)和G單元用樁模塊代替。(如圖2.1所示)
4) 步驟5:測(cè)試E單元,通過(guò)已測(cè)試過(guò)的D單元調(diào)用它,而D單元是由已通過(guò)測(cè)試
的A單元來(lái)調(diào)用的,使用已通過(guò)測(cè)試的B和C單元,并且將F,G,H,I和J單元用樁模塊代替。
5) 步驟6:測(cè)試F單元,通過(guò)已測(cè)試過(guò)的D單元調(diào)用它,而D單元是由已通過(guò)測(cè)試
的A單元來(lái)調(diào)用的,使用已通過(guò)測(cè)試的B,C和E單元,并且將G,H,I和J單元用樁模塊代替。
6) 步驟7:測(cè)試G單元,通過(guò)已測(cè)試過(guò)的D單元調(diào)用它,而D單元是由已通過(guò)測(cè)試
的A單元來(lái)調(diào)用的,使用已通過(guò)測(cè)試的B,C和F單元,并且將H,I和J單元用樁模塊代替。
7) 步驟8:測(cè)試H單元,通過(guò)已測(cè)試過(guò)的E單元調(diào)用它,而E單元是由已通過(guò)測(cè)試的D單元來(lái)調(diào)用的,而D單元是由已通過(guò)測(cè)試的A單元來(lái)調(diào)用的,使用已通過(guò)測(cè)試的B,C,E,F(xiàn),G和H單元,并且將J單元用樁模塊代替。
8) 步驟9:測(cè)試J單元,通過(guò)已測(cè)試過(guò)的E單元調(diào)用它,而E單元是由已通過(guò)測(cè)試的
D單元來(lái)調(diào)用的,而D單元是由已通過(guò)測(cè)試的A單元來(lái)調(diào)用的,使用已通過(guò)測(cè)試的B,C,E,F(xiàn),G,H和I單元
2.2 優(yōu)點(diǎn)
自上而下單元測(cè)試法提供了一種軟件集成階段之前的較早的單元集成方法。實(shí)際上,自上而下單元測(cè)試法確實(shí)將單元測(cè)試和軟件集成策略進(jìn)行了組合。
單元的詳細(xì)設(shè)計(jì)是自上而下的,自上而下的測(cè)試實(shí)現(xiàn)過(guò)程使得被測(cè)單元按照原設(shè)計(jì)的順序進(jìn)行,因?yàn)閱卧獪y(cè)試的詳細(xì)設(shè)計(jì)與軟件生命周期代碼設(shè)計(jì)階段的重疊,所以開(kāi)發(fā)時(shí)間將被縮短。
在通常的結(jié)構(gòu)化設(shè)計(jì)中,高等級(jí)的單元提供高層的功能,而低等級(jí)的單元實(shí)現(xiàn)細(xì)節(jié),自上而下的單元測(cè)試將提供一種早期的“可見(jiàn)”的功能化集成。它給予單元測(cè)試一種必要的合理的實(shí)現(xiàn)途徑。
較低層次的多余功能可以通過(guò)自上而下法來(lái)鑒別,這是因?yàn)闆](méi)有路徑來(lái)測(cè)試它。(但是,這可能在區(qū)分多余的功能和沒(méi)有被測(cè)試的功能時(shí)帶來(lái)困難)。
2.3 缺點(diǎn)
自上而下法是通過(guò)樁模塊來(lái)進(jìn)行控制的,而且測(cè)試用例常常涉及很多的樁模塊。對(duì)于每個(gè)已測(cè)單元來(lái)說(shuō),測(cè)試變得越來(lái)越復(fù)雜,結(jié)果是開(kāi)發(fā)和維護(hù)的費(fèi)用也越來(lái)越昂貴。
依層次進(jìn)行的自上而下的測(cè)試,要達(dá)到一個(gè)好的覆蓋結(jié)構(gòu)也很困難,而這對(duì)于一個(gè)較為完善、安全的關(guān)鍵性應(yīng)用來(lái)說(shuō)至為重要,同時(shí)這也是很多的標(biāo)準(zhǔn)所要求的。難于達(dá)到一個(gè)好的覆蓋結(jié)構(gòu)也可能導(dǎo)致最終的多余功能和未測(cè)試功能之間的混亂。由此,測(cè)試一些低層次的功能,特別是錯(cuò)誤處理代碼,將徹底不切實(shí)。
一個(gè)單元的變化往往會(huì)影響對(duì)其兄弟單元和下層單元的測(cè)試。例如,考慮一下D單元一個(gè)變化。很明顯,對(duì)D單元的單元測(cè)試不得不發(fā)生變化和重新進(jìn)行。另外,要使用已測(cè)試單元D的E、F、G、H、I和J單元也不得不重新測(cè)試。作為單元D改變的結(jié)果,上述測(cè)試自身可能也不得不發(fā)生改變,即使單元E、F、G、H、I和J實(shí)際上并沒(méi)有改變。這將導(dǎo)致當(dāng)變化發(fā)生時(shí),重復(fù)測(cè)試帶來(lái)的高成本,以及高額的維護(hù)成本和高額的整個(gè)軟件生產(chǎn)周期的成本。
在為自上而下測(cè)試法設(shè)計(jì)測(cè)試用例當(dāng)中,當(dāng)被測(cè)單元調(diào)用其他單元時(shí)需要測(cè)試人員具備結(jié)構(gòu)化知識(shí)。被測(cè)試單元的順序受限于單元的層次結(jié)構(gòu),低層次的單元必須要等到高層次的單元被測(cè)試后才能被測(cè)試,這樣就形成了一個(gè)“又長(zhǎng)又瘦”的單元測(cè)試階段。(然而,這可能會(huì)導(dǎo)致測(cè)試詳細(xì)設(shè)計(jì)與軟件生命周期編碼階段的整體重疊。)
如圖2.1所示的例子程序中各個(gè)單元之間的層次關(guān)系十分簡(jiǎn)單,在實(shí)際的編程過(guò)程中可能會(huì)遇到類(lèi)似的情形,而且各個(gè)單元之間的層次關(guān)系會(huì)更復(fù)雜。所以自上而下測(cè)試法的缺點(diǎn)對(duì)單元測(cè)試造成的不利影響會(huì)隨著被測(cè)單元之間復(fù)雜的聯(lián)系而加深。
2.4 總結(jié)
一個(gè)自上而下的測(cè)試策略成本將高于基于分離的測(cè)試策略,這取決于頂層單元下層單元的復(fù)雜程度,以及由于下層單元自身發(fā)生變化所帶來(lái)的顯著影響。對(duì)于單元測(cè)試來(lái)說(shuō)自上而下的組織方法不是一個(gè)好的選擇。然而,當(dāng)各個(gè)組成單元已經(jīng)被單獨(dú)測(cè)試的情況下,用自上而下法進(jìn)行單元的集成測(cè)試是個(gè)不錯(cuò)的手段。
3. 自下而上法 3.1 詳述
在自下而上的單元測(cè)試中,被測(cè)單元與調(diào)用被測(cè)單元的單元是分開(kāi)測(cè)試的,但是測(cè)試時(shí)所使用的是真實(shí)的被調(diào)用單元。
測(cè)試時(shí)最底層的單元首先被測(cè)試,這樣就方便了對(duì)高層次單元的測(cè)試。然后使用前面已經(jīng)被測(cè)試過(guò)的被調(diào)用單元來(lái)測(cè)試其他的單元。重復(fù)這個(gè)過(guò)程直到最高層的單元被測(cè)試為止。自下而上法需要測(cè)試驅(qū)動(dòng),但是不需要測(cè)試樁。
圖3.1說(shuō)明了測(cè)試D單元時(shí)需要的測(cè)試驅(qū)動(dòng)和已測(cè)單元的情況,假設(shè)單元E、F、G、H、I和J已經(jīng)通過(guò)自下而上法進(jìn)行了測(cè)試。
圖3.1顯示了一個(gè)程序的單元測(cè)試的測(cè)試計(jì)劃,該計(jì)劃使用了基于自下而上的組織方法,其過(guò)程如下: 步驟(1)(注意在測(cè)試步驟中測(cè)試的順序不是最主要的,步驟1中的所有測(cè)試可以同步進(jìn)行)。
1) 測(cè)試單元H,在調(diào)用H單元的E單元處使用一個(gè)測(cè)試驅(qū)動(dòng); 2) 測(cè)試單元I,在調(diào)用I單元的E單元處使用一個(gè)測(cè)試驅(qū)動(dòng); 3) 測(cè)試單元J,在調(diào)用J單元的E單元處使用一個(gè)測(cè)試驅(qū)動(dòng); 4) 測(cè)試單元F,在調(diào)用F單元的D單元處使用一個(gè)測(cè)試驅(qū)動(dòng); 5) 測(cè)試單元G,在調(diào)用G單元的D單元處使用一個(gè)測(cè)試驅(qū)動(dòng); 6) 測(cè)試單元B,在調(diào)用B單元的A單元處使用一個(gè)測(cè)試驅(qū)動(dòng); 7) 測(cè)試單元C,在調(diào)用C單元的A單元處使用一個(gè)測(cè)試驅(qū)動(dòng)。 步驟(2)
測(cè)試單元E,在調(diào)用E單元的D單元處使用一個(gè)測(cè)試驅(qū)動(dòng),再加上已測(cè)試過(guò)的單元H、I和J。 步驟(3)
測(cè)試單元D,在調(diào)用D單元的A單元處使用一個(gè)測(cè)試驅(qū)動(dòng),再加上已測(cè)試過(guò)的單元E、F、G、H、I和J。(如圖3.1所示) 步驟(4)
測(cè)試單元A,使用已測(cè)試過(guò)的單元B、C、D、E、F、G、H、I和J。
3.2 優(yōu)點(diǎn)
和自上而下法一樣,自下而上單元測(cè)試法提供了一種比軟件集成階段更早的單元集成。自下而上單元測(cè)試同樣也是真正意義上的單元測(cè)試和軟件集成策略的結(jié)合。因?yàn)椴恍枰獪y(cè)試樁,所以所有的測(cè)試用例都由測(cè)試驅(qū)動(dòng)控制。這樣就使得低層次單元附近的單元測(cè)試相對(duì)簡(jiǎn)單些。(但是,高層次單元的測(cè)試可能會(huì)變得很復(fù)雜。)
在使用自下而上法測(cè)試時(shí),測(cè)試用例的編寫(xiě)可能只需要功能性的設(shè)計(jì)信息,不需要結(jié)構(gòu)化的設(shè)計(jì)信息(盡管結(jié)構(gòu)化設(shè)計(jì)信息可能有利于實(shí)現(xiàn)測(cè)試的全覆蓋)。所以當(dāng)詳細(xì)的設(shè)計(jì)文檔缺乏結(jié)構(gòu)化的細(xì)節(jié)時(shí),自下而上的單元測(cè)試就變得十分有用處。
自下而上單元測(cè)試法提供了一種低層次功能性的集成,而較高層次的功能隨著單元測(cè)試過(guò)程的進(jìn)行按照單元層次關(guān)系逐層增加。這就使得自下而上單元測(cè)試很容易地與測(cè)試對(duì)象相兼容。
3.3 缺點(diǎn)
隨著測(cè)試逐層推進(jìn),自下而上單元測(cè)試變得越來(lái)越復(fù)雜,隨之而來(lái)的是開(kāi)發(fā)和維護(hù)的成本越來(lái)越高昂,同樣要實(shí)現(xiàn)好的結(jié)構(gòu)覆蓋也變得越來(lái)越困難。
低層單元的變化經(jīng)常影響其上層單元的測(cè)試。例如:想象一下H單元發(fā)生變化的情況。很明顯,對(duì)H單元的測(cè)試不得不發(fā)生變化和重新進(jìn)行。另外,對(duì)于A(yíng)、D和E單元的測(cè)試來(lái)說(shuō),因?yàn)樗鼈児餐褂昧艘褱y(cè)試過(guò)的H單元,所以它們的測(cè)試也不得不重做。作為H單元發(fā)生變化的后果,這些測(cè)試本身可能也要進(jìn)行改變,即使單元A、D和E實(shí)際上并沒(méi)有發(fā)生變化。這就導(dǎo)致了當(dāng)變化發(fā)生時(shí),產(chǎn)生了與重新測(cè)試有關(guān)的高額代價(jià),以及高額的維護(hù)成本和整個(gè)軟件生命周期成本的提高。
單元測(cè)試的順序取決于單元的層次關(guān)系,較高層次的單元必須要等到較低層次單元通過(guò)測(cè)試后才能進(jìn)行測(cè)試,所以就形成了“長(zhǎng)瘦”型的單元測(cè)試階段。最先被測(cè)試的單元是最后被設(shè)計(jì)的單元,所以單元測(cè)試不能與軟件生命周期的詳細(xì)設(shè)計(jì)階段重疊。
如圖2.2所示的例子程序中各個(gè)單元之間的層次關(guān)系十分簡(jiǎn)單,在實(shí)際的編程過(guò)程中可能會(huì)遇到類(lèi)似的情形,而且各個(gè)單元之間的層次關(guān)系會(huì)更復(fù)雜。與自上而下測(cè)試法一樣,自下而上測(cè)試法的缺點(diǎn)會(huì)隨著被測(cè)單元之間復(fù)雜的聯(lián)系而放大。
3.4 總結(jié)
自下而上組織法對(duì)于單元測(cè)試來(lái)說(shuō)是個(gè)比較好的手段,特別是當(dāng)測(cè)試對(duì)象和重用情況時(shí)。然而,自下而上方法偏向于功能性測(cè)試,而不是結(jié)構(gòu)化測(cè)試。對(duì)于很多標(biāo)準(zhǔn)所需要的高集成度和安全的關(guān)鍵性應(yīng)用,需要達(dá)到高層次的結(jié)構(gòu)覆蓋,但自下而上法很難滿(mǎn)足這個(gè)要求。
自下而上單元測(cè)試法與很多軟件開(kāi)發(fā)所要求的緊湊的時(shí)間計(jì)劃是相沖突的。總的來(lái)說(shuō),一個(gè)自下而上策略成本將高于基于分離的測(cè)試策略,這是因?yàn)閱卧獙哟谓Y(jié)構(gòu)中低層次單元以上單元的復(fù)雜程度和它們發(fā)生變化所帶來(lái)的顯著影響。
4. 分離法 4.1 詳述
分離測(cè)試法是分開(kāi)測(cè)試每一個(gè)單元,無(wú)論是被調(diào)用單元還是調(diào)用單元。被測(cè)單元可以按照任意順序進(jìn)行測(cè)試,因?yàn)楸粶y(cè)單元不需要其他任何已測(cè)單元的支持。每一個(gè)單元的測(cè)試都需要一個(gè)測(cè)試驅(qū)動(dòng),并且所有的被調(diào)用單元都要用測(cè)試樁代替。圖4.1 說(shuō)明了測(cè)試單元D 時(shí)需要的測(cè)試驅(qū)動(dòng)和測(cè)試樁的情況。
圖4.1 顯示了某個(gè)程序中一個(gè)單元的測(cè)試計(jì)劃,該計(jì)劃基于分離組織方法的策略,只需要如下所示的一步:
步驟(1)(注意該測(cè)試計(jì)劃只有一步。測(cè)試的順序不是最主要的,所有的測(cè)試可以同步進(jìn)行。)
1) 測(cè)試A 單元,使用一個(gè)測(cè)試驅(qū)動(dòng)啟動(dòng)測(cè)試,并且將B、C 和D 單元換成測(cè)試樁; 2) 測(cè)試B 單元,在A(yíng) 單元處使用一個(gè)測(cè)試驅(qū)動(dòng)來(lái)調(diào)用B 單元; 3) 測(cè)試C 單元,在A(yíng) 單元處使用一個(gè)測(cè)試驅(qū)動(dòng)來(lái)調(diào)用C 單元;
4) 測(cè)試D 單元,在A(yíng) 單元處使用一個(gè)測(cè)試驅(qū)動(dòng)來(lái)調(diào)用D 單元,并且將E、F和G
單元換成測(cè)試樁(如圖3.1 所示);
5) 測(cè)試E 單元,在D 單元處使用一個(gè)測(cè)試驅(qū)動(dòng)來(lái)調(diào)用E 單元,并且將H、I和J
單元換成測(cè)試樁;
6) 測(cè)試F 單元,在D 單元處使用一個(gè)測(cè)試驅(qū)動(dòng)來(lái)調(diào)用F 單元; 7) 測(cè)試G 單元,在D 單元處使用一個(gè)測(cè)試驅(qū)動(dòng)來(lái)調(diào)用G 單元; 8) 測(cè)試H 單元,在E 單元處使用一個(gè)測(cè)試驅(qū)動(dòng)來(lái)調(diào)用H 單元; 9) 測(cè)試I 單元,在E 單元處使用一個(gè)測(cè)試驅(qū)動(dòng)來(lái)調(diào)用I 單元; 10) 測(cè)試J 單元,在E 單元處使用一個(gè)測(cè)試驅(qū)動(dòng)來(lái)調(diào)用J 單元。
4.2 優(yōu)點(diǎn)
徹底地測(cè)試一個(gè)分離的單元是很容易做到的,單元測(cè)試將其從與其它單元之間復(fù)雜的關(guān)系中分離了出來(lái)。分離測(cè)試是最容易實(shí)現(xiàn)良好的結(jié)構(gòu)性覆蓋的方法,并且實(shí)現(xiàn)良好結(jié)構(gòu)性覆蓋的困難程度與確定某一個(gè)單元在單元層次中所處位置的難易度沒(méi)有什么不同。
因?yàn)槊恳淮沃粶y(cè)試一個(gè)單元,所以該方法中所使用的測(cè)試驅(qū)動(dòng)比自下而上法中所使用的測(cè)試驅(qū)動(dòng)簡(jiǎn)單,該方法中所使用的測(cè)試樁比自上而下法中使用的測(cè)試樁簡(jiǎn)單。由于采用了分離的方法進(jìn)行單元測(cè)試,被測(cè)單元之間沒(méi)有依賴(lài)關(guān)系,所以單元測(cè)試階段可以和詳細(xì)設(shè)計(jì)階段,以及軟件生命周期的代碼編寫(xiě)階段重疊。所有單元都能同步測(cè)試,形成了單元測(cè)試階段“短而寬”的特點(diǎn)。這有利于通過(guò)擴(kuò)大團(tuán)隊(duì)規(guī)模的手段縮短整個(gè)軟件開(kāi)發(fā)的時(shí)間。分離測(cè)試法另外一個(gè)優(yōu)點(diǎn)是去除了測(cè)試單元之間的內(nèi)部依賴(lài)關(guān)系,所以當(dāng)一個(gè)單元發(fā)生變化時(shí)只需要改變那個(gè)發(fā)生變化的測(cè)試單元,而對(duì)其它測(cè)試單元沒(méi)有任何影響。由此可以看出分離組織法的成本要低于自下而上組織法和自上而下組織法,特別是當(dāng)發(fā)生變化時(shí)其效果更加明顯。
分離法提供了一種與集成測(cè)試不同的單元測(cè)試分離手段,它允許開(kāi)發(fā)人員在軟件生命周期的單元測(cè)試階段專(zhuān)心致力于單元測(cè)試工作,而在軟件生命周期的集成測(cè)試階段專(zhuān)心致力于集成測(cè)試工作。只有分離法是純粹意義上適用于單元測(cè)試的方法,自上而下測(cè)試法和自下而上測(cè)試法適用于單元測(cè)試和集成階段的混合過(guò)程。與自上而下法和自下而上法不同的是,用分離法進(jìn)行的單元測(cè)試,被測(cè)單元不會(huì)受到與其關(guān)聯(lián)的其它任何單元的影響。
4.3 缺點(diǎn)
用分離法進(jìn)行單元測(cè)試最主要的缺點(diǎn)是它不能提供一個(gè)早期的單元集成。這必須要等到軟件生命周期的集成階段才能做到。(這很難說(shuō)是一個(gè)真正的缺點(diǎn))
用分離法進(jìn)行單元測(cè)試時(shí)需要結(jié)構(gòu)設(shè)計(jì)信息和使用測(cè)試樁、測(cè)試驅(qū)動(dòng)。這會(huì)導(dǎo)致在測(cè)試靠近底層的單元時(shí),所花費(fèi)成本要高于自下而上法。然而,這個(gè)缺陷可以通過(guò)簡(jiǎn)化層次較高的單元的測(cè)試,以及每個(gè)單元每次發(fā)生變化時(shí)的較低花費(fèi)得到補(bǔ)償。
4.4 總結(jié)
用分離法進(jìn)行單元測(cè)試是最合適的選擇。在加上適當(dāng)?shù)募刹呗宰鳛檠a(bǔ)充,將會(huì)縮短軟件開(kāi)發(fā)時(shí)間所占比例和降低開(kāi)發(fā)費(fèi)用,這個(gè)優(yōu)勢(shì)將會(huì)貫穿整個(gè)軟件開(kāi)發(fā)過(guò)程和軟件生命周期。按照分離法進(jìn)行單元測(cè)試時(shí),被測(cè)單元可以按照自上而下或者自下而上的順序進(jìn)行集成,或者集成為任何便利的群組和群組的結(jié)合。然而,一個(gè)自下而上的集成方式是與目前流行的面向?qū)ο蠛兔嫦驅(qū)ο蟮脑O(shè)計(jì)最相兼容的策略。分離法單元測(cè)試是實(shí)現(xiàn)高層次結(jié)構(gòu)覆蓋的最佳手段,而高層次結(jié)構(gòu)覆蓋對(duì)于很多標(biāo)準(zhǔn)所要求的高完善性和安全的關(guān)鍵性應(yīng)用來(lái)說(shuō)是至關(guān)重要。在通過(guò)單元測(cè)試完成了所有實(shí)現(xiàn)好的結(jié)構(gòu)覆蓋的困難工作的基礎(chǔ)上,集成測(cè)試就可以集中于全面的功能測(cè)試和單元交互的測(cè)試。
5. 使用AdaTEST 和Cantata
一個(gè)單元的測(cè)試在整個(gè)軟件生命周期中要重復(fù)進(jìn)行很多次,無(wú)論是在開(kāi)發(fā)階段還是維護(hù)過(guò)程中。一些測(cè)試工具如:AdaTEST 和Cantata,可以用于一些易于重復(fù)進(jìn)行和花費(fèi)較少的自動(dòng)化單元測(cè)試中,這樣可以有效降低人為因素帶來(lái)的風(fēng)險(xiǎn)。AdaTEST 和Cantata 測(cè)試腳本由一個(gè)測(cè)試驅(qū)動(dòng)和一個(gè)樁的集合(可選的)組成。AdaTEST 和Cantata 可以用于本文所介紹的任何單元測(cè)試的組織方法,或者這些方法的任意組合,使得開(kāi)發(fā)人員可以采用最適合于項(xiàng)目應(yīng)用的測(cè)試策略。IPL 提供了兩篇相關(guān)論文,如下所示:
“Achieving Testability when using Ada Packaging and Data Hiding Methods”“Testing C++ Objects”,論文“Testing C++ Objects”同樣詳細(xì)討論了在用自下而上法進(jìn)行單元測(cè)試時(shí),分離的類(lèi)和層次等級(jí)的約束是如何引發(fā)問(wèn)題的。文章介紹了分離單元測(cè)試法是如何成為唯一實(shí)用的處理分離的類(lèi)和層次等級(jí)約束的途徑
變那個(gè)發(fā)生變化的測(cè)試單元,而對(duì)其它測(cè)試單元沒(méi)有任何影響。由此可以看出分離組織法的成本要低于自下而上組織法和自上而下組織法,特別是當(dāng)發(fā)生變化時(shí)其效果更加明顯。
分離法提供了一種與集成測(cè)試不同的單元測(cè)試分離手段,它允許開(kāi)發(fā)人員在軟件生命周期的單元測(cè)試階段專(zhuān)心致力于單元測(cè)試工作,而在軟件生命周期的集成測(cè)試階段專(zhuān)心致力于集成測(cè)試工作。只有分離法是純粹意義上適用于單元測(cè)試的方法,自上而下測(cè)試法和自下而上測(cè)試法適用于單元測(cè)試和集成階段的混合過(guò)程。與自上而下法和自下而上法不同的是,用分離法進(jìn)行的單元測(cè)試,被測(cè)單元不會(huì)受到與其關(guān)聯(lián)的其它任何單元的影響。
4.3 缺點(diǎn)
用分離法進(jìn)行單元測(cè)試最主要的缺點(diǎn)是它不能提供一個(gè)早期的單元集成。這必須要等到軟件生命周期的集成階段才能做到。(這很難說(shuō)是一個(gè)真正的缺點(diǎn))
用分離法進(jìn)行單元測(cè)試時(shí)需要結(jié)構(gòu)設(shè)計(jì)信息和使用測(cè)試樁、測(cè)試驅(qū)動(dòng)。這會(huì)導(dǎo)致在測(cè)試靠近底層的單元時(shí),所花費(fèi)成本要高于自下而上法。然而,這個(gè)缺陷可以通過(guò)簡(jiǎn)化層次較高的單元的測(cè)試,以及每個(gè)單元每次發(fā)生變化時(shí)的較低花費(fèi)得到補(bǔ)償。
4.4 總結(jié)
用分離法進(jìn)行單元測(cè)試是最合適的選擇。在加上適當(dāng)?shù)募刹呗宰鳛檠a(bǔ)充,將會(huì)縮短軟件開(kāi)發(fā)時(shí)間所占比例和降低開(kāi)發(fā)費(fèi)用,這個(gè)優(yōu)勢(shì)將會(huì)貫穿整個(gè)軟件開(kāi)發(fā)過(guò)程和軟件生命周期。按照分離法進(jìn)行單元測(cè)試時(shí),被測(cè)單元可以按照自上而下或者自下而上的順序進(jìn)行集成,或者集成為任何便利的群組和群組的結(jié)合。然而,一個(gè)自下而上的集成方式是與目前流行的面向?qū)ο蠛兔嫦驅(qū)ο蟮脑O(shè)計(jì)最相兼容的策略。分離法單元測(cè)試是實(shí)現(xiàn)高層次結(jié)構(gòu)覆蓋的最佳手段,而高層次結(jié)構(gòu)覆蓋對(duì)于很多標(biāo)準(zhǔn)所要求的高完善性和安全的關(guān)鍵性應(yīng)用來(lái)說(shuō)是至關(guān)重要。在通過(guò)單元測(cè)試完成了所有實(shí)現(xiàn)好的結(jié)構(gòu)覆蓋的困難工作的基礎(chǔ)上,集成測(cè)試就可以集中于全面的功能測(cè)試和單元交互的測(cè)試。
5. 使用AdaTEST 和Cantata
一個(gè)單元的測(cè)試在整個(gè)軟件生命周期中要重復(fù)進(jìn)行很多次,無(wú)論是在開(kāi)發(fā)階段還是維護(hù)過(guò)程中。一些測(cè)試工具如:AdaTEST 和Cantata,可以用于一些易于重復(fù)進(jìn)行和花費(fèi)較少的自動(dòng)化單元測(cè)試中,這樣可以有效降低人為因素帶來(lái)的風(fēng)險(xiǎn)。AdaTEST 和Cantata 測(cè)試腳本由一個(gè)測(cè)試驅(qū)動(dòng)和一個(gè)樁的集合(可選的)組成。AdaTEST 和Cantata 可以用于本文所介紹的任何單元測(cè)試的組織方法,或者這些方法的任意組合,使得開(kāi)發(fā)人員可以采用最適合于項(xiàng)目應(yīng)用的測(cè)試策略。IPL 提供了兩篇相關(guān)論文,如下所示:
“Achieving Testability when using Ada Packaging and Data Hiding Methods”“Testing C++ Objects”,論文“Testing C++ Objects”同樣詳細(xì)討論了在用自下而上法進(jìn)行單元測(cè)試時(shí),分離的類(lèi)和層次等級(jí)的約束是如何引發(fā)問(wèn)題的。文章介紹了分離單元測(cè)試法是如何成為唯一實(shí)用的處理分離的類(lèi)和層次等級(jí)約束的途徑
評(píng)論