|
|
服務(wù)熱線:400-669-0203 020-29178595 QQ2557064750 2649046091 http://www.simou.net.cn/ http://www.innor.org/
單元測(cè)試(unit testing),是指對(duì)軟件中的最小可測(cè)試單元進(jìn)行檢查和驗(yàn)證。對(duì)于單元測(cè)試中單元的含義,一般來(lái)說(shuō),要根據(jù)實(shí)際情況去判定其具體含義,如C語(yǔ)言中單元指一個(gè)函數(shù),Java里單元指一個(gè)類,圖形化的軟件中可以指一個(gè)窗口或一個(gè)菜單等。總的來(lái)說(shuō),單元就是人為規(guī)定的最小的被測(cè)功能模塊。單元測(cè)試是在軟件開(kāi)發(fā)過(guò)程中要進(jìn)行的最低級(jí)別的測(cè)試活動(dòng),軟件的獨(dú)立單元將在與程序的其他部分相隔離的情況下進(jìn)行測(cè)試。
在一種傳統(tǒng)的結(jié)構(gòu)化編程語(yǔ)言中,比如C,要進(jìn)行測(cè)試的單元一般是函數(shù)或子過(guò)程。在像C++這樣的面向?qū)ο蟮恼Z(yǔ)言中, 要進(jìn)行測(cè)試的基本單元是類。對(duì)Ada語(yǔ)言來(lái)說(shuō),開(kāi)發(fā)人員可以選擇是在獨(dú)立的過(guò)程和函數(shù),還是在Ada包的級(jí)別上進(jìn)行單元測(cè)試。單元測(cè)試的原則同樣被擴(kuò)展到第四代語(yǔ)言(4GL)的開(kāi)發(fā)中,在這里基本單元被典型地劃分為一個(gè)菜單或顯示界面。
經(jīng)常與單元測(cè)試聯(lián)系起來(lái)的另外一些開(kāi)發(fā)活動(dòng)包括代碼走讀(Code review),靜態(tài)分析(Static analysis)和動(dòng)態(tài)分析(Dynamic analysis)。靜態(tài)分析就是對(duì)軟件的源代碼進(jìn)行研讀,查找錯(cuò)誤或收集一些度量數(shù)據(jù),并不需要對(duì)代碼進(jìn)行編譯和執(zhí)行。動(dòng)態(tài)分析就是通過(guò)觀察軟件運(yùn)行時(shí)的動(dòng)作,來(lái)提供執(zhí)行跟蹤,時(shí)間分析,以及測(cè)試覆蓋度方面的信息。
基本介紹
單元測(cè)試(模塊測(cè)試)是開(kāi)發(fā)者編寫(xiě)的一小段代碼,用于檢驗(yàn)被測(cè)代碼的一個(gè)很小的、很明確的功能是否正確。通常而言,一個(gè)單元測(cè)試是用于判斷某個(gè)特定條件(或者場(chǎng)景)下某個(gè)特定函數(shù)的行為。
折疊編輯本段測(cè)試介紹
在一種傳統(tǒng)的結(jié)構(gòu)化編程語(yǔ)言中,比如C,要進(jìn)行測(cè)試的單元一般是函數(shù)或子過(guò)程。在象C++這樣的面向?qū)ο蟮恼Z(yǔ)言中, 要進(jìn)行測(cè)試的基本單元是類。對(duì)Ada語(yǔ)言來(lái)說(shuō),開(kāi)發(fā)人員可以選擇是在獨(dú)立的過(guò)程和函數(shù),還是在Ada包的級(jí)別上進(jìn)行單元測(cè)試。單元測(cè)試的原則同樣被擴(kuò)展到第四代語(yǔ)言(4GL)的開(kāi)發(fā)中,在這里基本單元被典型地劃分為一個(gè)菜單或顯示界面。
經(jīng)常與單元測(cè)試聯(lián)系起來(lái)的另外一些開(kāi)發(fā)活動(dòng)包括代碼走讀(Code review),靜態(tài)分析(Static analysis)和動(dòng)態(tài)分析(Dynamic analysis)。靜態(tài)分析就是對(duì)軟件的源代碼進(jìn)行研讀,查找錯(cuò)誤或收集一些度量數(shù)據(jù),并不需要對(duì)代碼進(jìn)行編譯和執(zhí)行。動(dòng)態(tài)分析就是通過(guò)觀察軟件運(yùn)行時(shí)的動(dòng)作,來(lái)提供執(zhí)行跟蹤,時(shí)間分析,以及測(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è)試,就是為了證明這段代碼的行為和我們期望的一致。
工廠在組裝一臺(tái)電視機(jī)之前,會(huì)對(duì)每個(gè)元件都進(jìn)行測(cè)試,這,就是單元測(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)力。可以說(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ù)勎业目捶ā?
一般認(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è)試
我們編寫(xiě)代碼時(shí),一定會(huì)反復(fù)調(diào)試保證它能夠編譯通過(guò)。如果是編譯沒(méi)有通過(guò)的代碼,沒(méi)有任何人會(huì)愿意交付給自己的老板。但代碼通過(guò)編譯,只是說(shuō)明了它的語(yǔ)法正確;我們卻無(wú)法保證它的語(yǔ)義也一定正確,沒(méi)有任何人可以輕易承諾這段代碼的行為一定是正確的。
幸運(yùn)的是,單元測(cè)試會(huì)為我們的承諾做保證。編寫(xiě)單元測(cè)試就是用來(lái)驗(yàn)證這段代碼的行為是否與我們期望的一致。有了單元測(cè)試,我們可以自信的交付自己的代碼,而沒(méi)有任何的后顧之憂。
什么時(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ù)表、返回類型都應(yīng)該確定下來(lái)了,所編寫(xiě)的測(cè)試代碼以后需修改的可能性比較小。
由誰(shuí)測(cè)試?單元測(cè)試與其他測(cè)試不同,單元測(cè)試可看作是編碼工作的一部分,應(yīng)該由程序員完成,也就是說(shuō),經(jīng)過(guò)了單元測(cè)試的代碼才是已完成的代碼,提交產(chǎn)品代碼時(shí)也要同時(shí)提交測(cè)試代碼。測(cè)試部門(mén)可以作一定程度的審核。
關(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ò)誤。
在一種傳統(tǒng)的結(jié)構(gòu)化編程語(yǔ)言中,比如C,要進(jìn)行測(cè)試的單元一般是函數(shù)或子過(guò)程。在象C++這樣的面向?qū)ο蟮恼Z(yǔ)言中, 要進(jìn)行測(cè)試的基本單元是類。對(duì)Ada語(yǔ)言來(lái)說(shuō),開(kāi)發(fā)人員可以選擇是在獨(dú)立的過(guò)程和函數(shù),還是在Ada包的級(jí)別上進(jìn)行單元測(cè)試。單元測(cè)試的原則同樣被擴(kuò)展到第四代語(yǔ)言(4GL)的開(kāi)發(fā)中,在這里基本單元被典型地劃分為一個(gè)菜單或顯示界面。
折疊一些流行的誤解
在明確了什么是單元測(cè)試以后,我們可以進(jìn)行"反調(diào)論證"了。在下面的章節(jié)里,我們列出了一些反對(duì)單元測(cè)試的普遍的論點(diǎn)。然后用充分的理由來(lái)證明這些論點(diǎn)是不足取的。
它浪費(fèi)了太多的時(shí)間
測(cè)試工具
現(xiàn)在開(kāi)始介紹單元測(cè)試工具,分別按編程語(yǔ)言進(jìn)行分組介紹。
折疊C/C++
CppUnit
首先是CppUnit,這是C++單元測(cè)試工具的鼻祖,免費(fèi)的開(kāi)源的單元測(cè)試框架。由于已有一眾高人寫(xiě)了不少關(guān)于CppUnit的很好的文章,老納就不現(xiàn)丑了,想了解CppUnit的朋友,建議讀一下Cpluser 所作的《CppUnit測(cè)試框架入門(mén)》,。該文也提供了CppUnit的下載地址。
C++Test
然后介紹C++Test,這是Parasoft公司的產(chǎn)品。[C++Test是一個(gè)功能強(qiáng)大的自動(dòng)化C/C++單元級(jí)測(cè)試工具,可以自動(dòng)測(cè)試任何C/C++函數(shù)、類,自動(dòng)生成測(cè)試用例、測(cè)試驅(qū)動(dòng)函數(shù)或樁函數(shù),在自動(dòng)化的環(huán)境下極其容易快速的將單元級(jí)的測(cè)試覆蓋率達(dá)到100%]。[]內(nèi)的文字引自,這是華唐公司的網(wǎng)頁(yè)。老納想寫(xiě)些介紹C++Test的文字,但發(fā)現(xiàn)無(wú)法超越華唐公司的網(wǎng)頁(yè)上的介紹,所以也就省點(diǎn)事了,想了解C++Test的朋友,建議訪問(wèn)該公司的網(wǎng)站。華唐公司代理C++Test,想要購(gòu)買(mǎi)或索取報(bào)價(jià)、試用版都可以找他們。
Visual Unit
最后介紹Visual Unit,簡(jiǎn)稱VU,這是國(guó)產(chǎn)的單元測(cè)試工具,據(jù)說(shuō)申請(qǐng)了多項(xiàng)專利,擁有一批創(chuàng)新的技術(shù),不過(guò)老納只關(guān)心是不是有用和好用。[自動(dòng)生成測(cè)試代碼 快速建立功能測(cè)試用例 程序行為一目了然 極高的測(cè)試完整性 高效完成白盒覆蓋 快速排錯(cuò) 高效調(diào)試 詳盡的測(cè)試報(bào)告]。[]內(nèi)的文字是VU開(kāi)發(fā)商的網(wǎng)頁(yè)上摘錄的,。前面所述測(cè)試要求:完成功能測(cè)試,完成語(yǔ)句覆蓋、條件覆蓋、分支覆蓋、路徑覆蓋,用VU可以輕松實(shí)現(xiàn),還有一點(diǎn)值得一提:使用VU還能提高編碼的效率,總體來(lái)說(shuō),在完成單元測(cè)試的同時(shí),編碼調(diào)試的時(shí)間還能大幅度縮短。算了,不想再講了,老納顯擺理論、介紹經(jīng)驗(yàn)還是有興趣的,因?yàn)榭梢詽M足老納好為人師的虛榮心,但介紹工具就覺(jué)得索然無(wú)味了,畢竟工具好不好用,合不合用,要試過(guò)才知道,還是自己去開(kāi)發(fā)商的網(wǎng)站看吧,可以下載演示版,還有演示課件。
gtest
gtest測(cè)試框架是在不同平臺(tái)上(Linux,Mac OS X,Windows,Cygwin,Windows CE和Symbian)為編寫(xiě)C++測(cè)試而生成的。它是基于xUnit架構(gòu)的測(cè)試框架,支持自動(dòng)發(fā)現(xiàn)測(cè)試,豐富的斷言集,用戶定義的斷言,death測(cè)試,致命與非致命的失敗,類型參數(shù)化測(cè)試,各類運(yùn)行測(cè)試的選項(xiàng)和XML的測(cè)試報(bào)告。需要詳細(xì)了解的朋友可以參閱《玩轉(zhuǎn)Google單元測(cè)試框架gtest系列》該篇文章。
折疊Java
JUnit
JUnit 是 Java 社區(qū)中知名度最高的單元測(cè)試工具。它誕生于 1997 年,由 Erich Gamma 和 Kent Beck 共同開(kāi)發(fā)完成。其中 Erich Gamma 是經(jīng)典著作《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書(shū)的作者之一,并在 Eclipse 中有很大的貢獻(xiàn);Kent Beck 則是一位極限編程(XP)方面的專家和先驅(qū)。JUnit 設(shè)計(jì)的非常小巧,但是功能卻非常強(qiáng)大。JUnit ——是一個(gè)開(kāi)發(fā)源代碼的Java測(cè)試框架,用于編寫(xiě)和運(yùn)行可重復(fù)的測(cè)試。他是用于單元測(cè)試框架體系xUnit的一個(gè)實(shí)例(用于java語(yǔ)言)。主要用于白盒測(cè)試,回歸測(cè)試。
JUnit的好處和JUnit單元測(cè)試編寫(xiě)原則:
好處:可以使測(cè)試代碼與產(chǎn)品代碼分開(kāi);針對(duì)某一個(gè)類的測(cè)試代碼通過(guò)較少的改動(dòng)便可以應(yīng)用于另一個(gè)類的測(cè)試;易于集成到測(cè)試人員的構(gòu)建過(guò)程中,JUnit和Ant的結(jié)合可以實(shí)施增量開(kāi)發(fā);JUnit是公開(kāi)源代碼的,可以進(jìn)行二次開(kāi)發(fā);可以方便地對(duì)JUnit進(jìn)行擴(kuò)展;
編寫(xiě)原則:是簡(jiǎn)化測(cè)試的編寫(xiě),這種簡(jiǎn)化包括測(cè)試框架的學(xué)習(xí)和實(shí)際測(cè)試單元的編寫(xiě);是使測(cè)試單元保持持久性;是可以利用既有的測(cè)試來(lái)編寫(xiě)相關(guān)的測(cè)試;
有興趣的朋友可以下下來(lái)仔細(xì)研究下。
JUnit-addons
對(duì)JUnit的一些補(bǔ)充,比如設(shè)置、獲取被測(cè)試對(duì)象的私有屬性的值,調(diào)用被測(cè)試對(duì)象的私有方法等。
常用類:junitx.util.PrivateAccessor
Spring 測(cè)試框架
可以測(cè)試基于Spring的應(yīng)用,通過(guò)配置文件和注解自動(dòng)組裝需要的單元測(cè)試對(duì)象。
提供了一些常用的J2EE Mock對(duì)象,比如HttpSession的Mock類等。
可以支持?jǐn)?shù)據(jù)庫(kù)自動(dòng)回滾,以防止對(duì)數(shù)據(jù)庫(kù)的單元測(cè)試(插入,刪除等)不可重復(fù)執(zhí)行,防止修改數(shù)據(jù)庫(kù)狀態(tài)等。
DJUnit
通過(guò)代碼自動(dòng)產(chǎn)生Mock對(duì)象,省去了自己手動(dòng)編寫(xiě)N多的Mock類。
此外,它的Eclipse插件還可以做到測(cè)試覆蓋率、分支統(tǒng)計(jì)。
EasyMock
功能同DJUnit,也是通過(guò)編程自動(dòng)Mock掉與測(cè)試對(duì)象無(wú)關(guān)的類,方法。
折疊編輯本段相關(guān)介紹
折疊范疇
如果要給單元測(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í),你所能期望這段代碼完成的功能。
折疊不寫(xiě)測(cè)試的借口
到這里,我們已經(jīng)列舉了使用單元測(cè)試的種種理由。也許,每個(gè)人都同意,是的,該做更多的測(cè)試。這種人人同意的事情還多著呢,是的,該多吃蔬菜,該戒煙,該多休息,該多鍛煉……這并不意味著我們中的所有人都會(huì)這么去做,不是嗎?
1、 編寫(xiě)單元測(cè)試太花時(shí)間了。
我們知道,在開(kāi)發(fā)時(shí)越早發(fā)現(xiàn)BUG,就能節(jié)省更多的時(shí)間,降低更多的風(fēng)險(xiǎn)。
下圖表摘自<<實(shí)用軟件度量>>(Capers Jones,McGraw-Hill 1991),它列出了準(zhǔn)備測(cè)試,執(zhí)行測(cè)試,和修改缺陷所花費(fèi)的時(shí)間(以一個(gè)功能點(diǎn)為基準(zhǔn)),這些數(shù)據(jù)顯示單元測(cè)試的成本效率大約是集成測(cè)試的兩倍,是系統(tǒng)測(cè)試的三倍(參見(jiàn)條形圖)。
術(shù)語(yǔ):域測(cè)試(Field test)意思是在軟件投入使用以后,針對(duì)某個(gè)領(lǐng)域所作的所有測(cè)試活動(dòng)。
如果你仍然認(rèn)為在編寫(xiě)產(chǎn)品代碼的時(shí)候,還是沒(méi)有時(shí)間編寫(xiě)測(cè)試代碼,那么請(qǐng)先考慮下面這些問(wèn)題:
1)、對(duì)于所編寫(xiě)的代碼,你在調(diào)試上面花了多少時(shí)間。
2)、對(duì)于以前你自認(rèn)為正確的代碼,而實(shí)際上這些代碼卻存在重大的bug,你花了多少時(shí)間在重新確認(rèn)這些代碼上面。
3)、對(duì)于一個(gè)別人報(bào)告的bug,你花了多少時(shí)間才找出導(dǎo)致這個(gè)bug 的源碼位置。
回答完這些問(wèn)題,你一定不再以“太花時(shí)間”作為拒絕單元測(cè)試的借口。
2、 運(yùn)行測(cè)試的時(shí)間太長(zhǎng)了。
合適的測(cè)試是不會(huì)讓這種情況發(fā)生的。實(shí)際上,大多數(shù)測(cè)試的執(zhí)行都是非常快的,因此你在幾秒之內(nèi)就可以運(yùn)行成千上萬(wàn)個(gè)測(cè)試。但是有時(shí)某些測(cè)試會(huì)花費(fèi)很長(zhǎng)的時(shí)間。這時(shí),需要把這些耗時(shí)的測(cè)試和其他測(cè)試分開(kāi)。通常可以每天運(yùn)行這種測(cè)試一次,或者幾天一次。
3、 測(cè)試代碼并不是我的工作。
你的工作就是保證代碼能夠正確的完成你的行為,恰恰相反,測(cè)試代碼正是你不可缺少的工作。
4、 我并不清楚代碼的行為,所以也就無(wú)從測(cè)試。
如果你實(shí)在不清楚代碼的行為,那么估計(jì)現(xiàn)在并不是編碼的時(shí)候。如果你并不知道代碼的行為,那么你又如何知道你編寫(xiě)的代碼是正確的呢
5、 但是這些代碼都能夠編譯通過(guò)。
我們前面已經(jīng)說(shuō)過(guò),代碼通過(guò)編譯只是驗(yàn)證它的語(yǔ)法通過(guò)。但并不能保證它的行為就一定正確。
6、 公司請(qǐng)我來(lái)是為了寫(xiě)代碼,而不是寫(xiě)測(cè)試。
公司付給你薪水是為了讓你編寫(xiě)產(chǎn)品代碼,而單元測(cè)試大體上是一個(gè)工具,是一個(gè)和編輯器、開(kāi)發(fā)環(huán)境、編譯器等處于同一位置的工具。
7、 如果我讓測(cè)試員或者QA(Quality Assurance)人員沒(méi)有工作,那么我會(huì)覺(jué)得很內(nèi)疚。
你并不需要擔(dān)心這些。請(qǐng)記住,我們?cè)诖酥皇钦務(wù)搯卧獪y(cè)試,而它只是一種針對(duì)源碼的、低層次的,為程序員而設(shè)計(jì)的測(cè)試。在整個(gè)項(xiàng)目中,還有其他的很多測(cè)試需要這些人來(lái)完成,如:功能測(cè)試、驗(yàn)收測(cè)試、性能測(cè)試、環(huán)境測(cè)試、有效性測(cè)試、正確性測(cè)試、正規(guī)分析等等。
8、 我的公司并不會(huì)讓我在真實(shí)系統(tǒng)中運(yùn)行單元測(cè)試。
我們所討論的只是針對(duì)開(kāi)發(fā)者的單元測(cè)試。也就是說(shuō),如果你可以在其他的環(huán)境下(例如在正式的產(chǎn)品系統(tǒng)中)運(yùn)行這些測(cè)試的話,那么它們就不再是單元測(cè)試,而是其他類型的測(cè)試了。實(shí)際上,你可以在你的本機(jī)運(yùn)行單元測(cè)試,使用你自己的數(shù)據(jù)庫(kù),或者使用mock 對(duì)象。
一旦編碼完成,開(kāi)發(fā)人員總是會(huì)迫切希望進(jìn)行軟件的集成工作,這樣他們就能夠看到實(shí)際的系統(tǒng)開(kāi)始啟動(dòng)工作了。這在外表上看來(lái)是一項(xiàng)明顯的進(jìn)步,而象單元測(cè)試這樣的活動(dòng)也許會(huì)被看作是通往這個(gè)階段點(diǎn)的道路上的障礙, 推遲了對(duì)整個(gè)系統(tǒng)進(jìn)行聯(lián)調(diào)這種真正有意思的工作啟動(dòng)的時(shí)間。
在這種開(kāi)發(fā)步驟中,真實(shí)意義上的進(jìn)步被外表上的進(jìn)步取代了。系統(tǒng)能夠正常工作的可能性是很小的,更多的情況是充滿了各式各樣的Bug。在實(shí)踐中,這樣一種開(kāi)發(fā)步驟常常會(huì)導(dǎo)致這樣的結(jié)果:軟件甚至無(wú)法運(yùn)行。更進(jìn)一步的結(jié)果是大量的時(shí)間將被花費(fèi)在跟蹤那些包含在獨(dú)立單元里的簡(jiǎn)單的Bug上面,在個(gè)別情況下,這些Bug也許是瑣碎和微不足道的,但是總的來(lái)說(shuō),他們會(huì)導(dǎo)致在軟件集成為一個(gè)系統(tǒng)時(shí)增加額外的工期, 而且當(dāng)這個(gè)系統(tǒng)投入使用時(shí)也無(wú)法確保它能夠可靠運(yùn)行。
在實(shí)踐工作中,進(jìn)行了完整計(jì)劃的單元測(cè)試和編寫(xiě)實(shí)際的代碼所花費(fèi)的精力大致上是相同的。一旦完成了這些單元測(cè)試工作,很多Bug將被糾正,在確信他們手頭擁有穩(wěn)定可靠的部件的情況下,開(kāi)發(fā)人員能夠進(jìn)行更高效的系統(tǒng)集成工作。這才是真實(shí)意義上的進(jìn)步,所以說(shuō)完整計(jì)劃下的單元測(cè)試是對(duì)時(shí)間的更高效的利用。而調(diào)試人員的不受控和散漫的工作方式只會(huì)花費(fèi)更多的時(shí)間而取得很少的好處。
使用AdaTEST和Cantata這樣的支持工具可以使單元測(cè)試更加簡(jiǎn)單和有效。但這不是必須的,單元測(cè)試即使是在沒(méi)有工具支持的情況下也是一項(xiàng)非常有意義的活動(dòng)。
它僅僅是證明這些代碼做了什么
這是那些沒(méi)有首先為每個(gè)單元編寫(xiě)一個(gè)詳細(xì)的規(guī)格說(shuō)明而直接跳到編碼階段的開(kāi)發(fā)人員提出的一條普遍的抱怨, 當(dāng)編碼完成以后并且面臨代碼測(cè)試任務(wù)的時(shí)候,他們就閱讀這些代碼并找出它實(shí)際上做了什么,把他們的測(cè)試工作基于已經(jīng)寫(xiě)好的代碼的基礎(chǔ)上。當(dāng)然,他們無(wú)法證明任何事情。所有的這些測(cè)試工作能夠表明的事情就是編譯器工作正常。是的,他們也許能夠抓住(希望能夠)罕見(jiàn)的編譯器Bug,但是他們能夠做的僅僅是這些。
如果他們首先寫(xiě)好一個(gè)詳細(xì)的規(guī)格說(shuō)明,測(cè)試能夠以規(guī)格說(shuō)明為基礎(chǔ)。代碼就能夠針對(duì)它的規(guī)格說(shuō)明,而不是針對(duì)自身進(jìn)行測(cè)試。這樣的測(cè)試仍然能夠抓住編譯器的Bug,同時(shí)也能找到更多的編碼錯(cuò)誤,甚至是一些規(guī)格說(shuō)明中的錯(cuò)誤。好的規(guī)格說(shuō)明可以使測(cè)試的質(zhì)量更高,所以最后的結(jié)論是高質(zhì)量的測(cè)試需要高質(zhì)量的規(guī)格說(shuō)明。
在實(shí)踐中會(huì)出現(xiàn)這樣的情況:一個(gè)開(kāi)發(fā)人員要面對(duì)測(cè)試一個(gè)單元時(shí)只給出單元的代碼而沒(méi)有規(guī)格說(shuō)明這樣吃力不討好的任務(wù)。你怎樣做才會(huì)有更多的收獲,而不僅僅是發(fā)現(xiàn)編譯器的Bug?第一步是理解這個(gè)單元原本要做什么, --- 不是它實(shí)際上做了什么。比較有效的方法是倒推出一個(gè)概要的規(guī)格說(shuō)明。這個(gè)過(guò)程的主要輸入條件是要閱讀那些程序代碼和注釋, 主要針對(duì)這個(gè)單元, 及調(diào)用它和被它調(diào)用的相關(guān)代碼。畫(huà)出流程圖是非常有幫助的,你可以用手工或使用某種工具。可以組織對(duì)這個(gè)概要規(guī)格說(shuō)明的走讀(Review),以確保對(duì)這個(gè)單元的說(shuō)明沒(méi)有基本的錯(cuò)誤, 有了這種最小程度的代碼深層說(shuō)明,就可以用它來(lái)設(shè)計(jì)單元測(cè)試了。
我是個(gè)很棒的程序員, 我是不是可以不進(jìn)行單元測(cè)試?
在每個(gè)開(kāi)發(fā)組織中都至少有一個(gè)這樣的開(kāi)發(fā)人員,他非常擅長(zhǎng)于編程,他們開(kāi)發(fā)的軟件總是在第一時(shí)間就可以正常運(yùn)行,因此不需要進(jìn)行測(cè)試。你是否經(jīng)常聽(tīng)到這樣的借口?
折疊測(cè)試用例設(shè)計(jì)
下面談?wù)劀y(cè)試用例設(shè)計(jì)。前面已經(jīng)說(shuō)了,測(cè)試用例的核心是輸入數(shù)據(jù)。預(yù)期輸出是依據(jù)輸入數(shù)據(jù)和程序功能來(lái)確定的,也就是說(shuō),對(duì)于某一程序,輸入數(shù)據(jù)確定了,預(yù)期輸出也就可以確定了,至于生成/銷毀被測(cè)試對(duì)象和運(yùn)行測(cè)試的語(yǔ)句,是所有測(cè)試用例都大同小異的,因此,我們討論測(cè)試用例時(shí),只討論輸入數(shù)據(jù)。
前面說(shuō)過(guò),輸入數(shù)據(jù)包括四類:參數(shù)、成員變量、全局變量、IO媒體,這四類數(shù)據(jù)中,只要所測(cè)試的程序需要執(zhí)行讀操作的,就要設(shè)定其初始值,其中,前兩類比較常用,后兩類較少用。顯然,把輸入數(shù)據(jù)的所有可能取值都進(jìn)行測(cè)試,是不可能也是無(wú)意義的,我們應(yīng)該用一定的規(guī)則選擇有代表性的數(shù)據(jù)作為輸入數(shù)據(jù),主要有三種:正常輸入,邊界輸入,非法輸入,每種輸入還可以分類,也就是平常說(shuō)的等價(jià)類法,每類取一個(gè)數(shù)據(jù)作為輸入數(shù)據(jù),如果測(cè)試通過(guò),可以肯定同類的其他輸入也是可以通過(guò)的。下面舉例說(shuō)明:
正常輸入
例如字符串的Trim函數(shù),功能是將字符串前后的空格去除,那么正常的輸入可以有四類:前面有空格;后面有空格;前后均有空格;前后均無(wú)空格。
邊界輸入
上例中空字符串可以看作是邊界輸入。
再如一個(gè)表示年齡的參數(shù),它的有效范圍是0-100,那么邊界輸入有兩個(gè):0和100。
非法輸入
非法輸入是正常取值范圍以外的數(shù)據(jù),或使代碼不能完成正常功能的輸入,如上例中表示年齡的參數(shù),小于0或大于100都是非法輸入,再如一個(gè)進(jìn)行文件操作的函數(shù),非法輸入有這么幾類:文件不存在;目錄不存在;文件正在被其他程序打開(kāi);權(quán)限錯(cuò)誤。
如果函數(shù)使用了外部數(shù)據(jù),則正常輸入是肯定會(huì)有的,而邊界輸入和非法輸入不是所有函數(shù)都有。一般情況下,即使沒(méi)有設(shè)計(jì)文檔,考慮以上三種輸入也可以找出函數(shù)的基本功能點(diǎn)。實(shí)際上,單元測(cè)試與代碼編寫(xiě)是“一體兩面”的關(guān)系,編碼時(shí)對(duì)上述三種輸入都是必須考慮的,否則代碼的健壯性就會(huì)成問(wèn)題。
白盒覆蓋
上面所說(shuō)的測(cè)試數(shù)據(jù)都是針對(duì)程序的功能來(lái)設(shè)計(jì)的,就是所謂的黑盒測(cè)試。單元測(cè)試還需要從另一個(gè)角度來(lái)設(shè)計(jì)測(cè)試數(shù)據(jù),即針對(duì)程序的邏輯結(jié)構(gòu)來(lái)設(shè)計(jì)測(cè)試用例,就是所謂的白盒測(cè)試。在老納看來(lái),如果黑盒測(cè)試是足夠充分的,那么白盒測(cè)試就沒(méi)有必要,可惜“足夠充分”只是一種理想狀態(tài),例如:真的是所有功能點(diǎn)都測(cè)試了嗎?程序的功能點(diǎn)是人為的定義,常常是不全面的;各個(gè)輸入數(shù)據(jù)之間,有些組合可能會(huì)產(chǎn)生問(wèn)題,怎樣保證這些組合都經(jīng)過(guò)了測(cè)試?難于衡量測(cè)試的完整性是黑盒測(cè)試的主要缺陷,而白盒測(cè)試恰恰具有易于衡量測(cè)試完整性的優(yōu)點(diǎn),兩者之間具有極好的互補(bǔ)性,例如:完成功能測(cè)試后統(tǒng)計(jì)語(yǔ)句覆蓋率,如果語(yǔ)句覆蓋未完成,很可能是未覆蓋的語(yǔ)句所對(duì)應(yīng)的功能點(diǎn)未測(cè)試。
白盒測(cè)試針對(duì)程序的邏輯結(jié)構(gòu)設(shè)計(jì)測(cè)試用例,用邏輯覆蓋率來(lái)衡量測(cè)試的完整性。邏輯單位主要有:語(yǔ)句、分支、條件、條件值、條件值組合,路徑。語(yǔ)句覆蓋就是覆蓋所有的語(yǔ)句,其他類推。另外還有一種判定條件覆蓋,其實(shí)是分支覆蓋與條件覆蓋的組合,在此不作討論。跟條件有關(guān)的覆蓋就有三種,解釋一下:條件覆蓋是指覆蓋所有的條件表達(dá)式,即所有的條件表達(dá)式都至少計(jì)算一次,不考慮計(jì)算結(jié)果;條件值覆蓋是指覆蓋條件的所有可能取值,即每個(gè)條件的取真值和取假值都要至少計(jì)算一次;條件值組合覆蓋是指覆蓋所有條件取值的所有可能組合。老納做過(guò)一些粗淺的研究,發(fā)現(xiàn)與條件直接有關(guān)的錯(cuò)誤主要是邏輯操作符錯(cuò)誤,例如:||寫(xiě)成&&,漏了寫(xiě)!什么的,采用分支覆蓋與條件覆蓋的組合,基本上可以發(fā)現(xiàn)這些錯(cuò)誤,另一方面,條件值覆蓋與條件值組合覆蓋往往需要大量的測(cè)試用例,因此,在老納看來(lái),條件值覆蓋和條件值組合覆蓋的效費(fèi)比偏低。老納認(rèn)為效費(fèi)比較高且完整性也足夠的測(cè)試要求是這樣的:完成功能測(cè)試,完成語(yǔ)句覆蓋、條件覆蓋、分支覆蓋、路徑覆蓋。做過(guò)單元測(cè)試的朋友恐怕會(huì)對(duì)老納提出的測(cè)試要求給予一個(gè)字的評(píng)價(jià):暈!或者兩個(gè)字的評(píng)價(jià):狂暈!因?yàn)檫@似乎是不可能的要求,要達(dá)到這種測(cè)試完整性,其測(cè)試成本是不可想象的,不過(guò),出家人不打逛語(yǔ),老納之所以提出這種測(cè)試要求,是因?yàn)槔靡恍┕ぞ撸梢栽谳^低的成本下達(dá)到這種測(cè)試要求,后面將會(huì)作進(jìn)一步介紹。
關(guān)于白盒測(cè)試用例的設(shè)計(jì),程序測(cè)試領(lǐng)域的書(shū)籍一般都有講述,普通方法是畫(huà)出程序的邏輯結(jié)構(gòu)圖如程序流程圖或控制流圖,根據(jù)邏輯結(jié)構(gòu)圖設(shè)計(jì)測(cè)試用例,這些是純粹的白盒測(cè)試,不是老納想推薦的方式。老納所推薦的方法是:先完成黑盒測(cè)試,然后統(tǒng)計(jì)白盒覆蓋率,針對(duì)未覆蓋的邏輯單位設(shè)計(jì)測(cè)試用例覆蓋它,例如,先檢查是否有語(yǔ)句未覆蓋,有的話設(shè)計(jì)測(cè)試用例覆蓋它,然后用同樣方法完成條件覆蓋、分支覆蓋和路徑覆蓋,這樣的話,既檢驗(yàn)了黑盒測(cè)試的完整性,又避免了重復(fù)的工作,用較少的時(shí)間成本達(dá)到非常高的測(cè)試完整性。不過(guò),這些工作可不是手工能完成的,必須借助于工具,后面會(huì)介紹可以完成這些工作的測(cè)試工具。
在真實(shí)世界里,每個(gè)人都會(huì)犯錯(cuò)誤。即使某個(gè)開(kāi)發(fā)人員可以抱著這種態(tài)度在很少的一些簡(jiǎn)單的程序中應(yīng)付過(guò)去。但真正的軟件系統(tǒng)是非常復(fù)雜的。真正的軟件系統(tǒng)不可以寄希望于沒(méi)有進(jìn)行廣泛的測(cè)試和Bug修改過(guò)程就可以正常工作。
編碼不是一個(gè)可以一次性通過(guò)的過(guò)程。在真實(shí)世界中,軟件產(chǎn)品必須進(jìn)行維護(hù)以對(duì)操作需求的改變作出反應(yīng), 并且要對(duì)最初的開(kāi)發(fā)工作遺留下來(lái)的Bug進(jìn)行修改。你希望依靠那些原始作者進(jìn)行修改嗎? 這些制造出這些未經(jīng)測(cè)試的原始代碼的資深專家們還會(huì)繼續(xù)在其他地方制造這樣的代碼。在開(kāi)發(fā)人員做出修改后進(jìn)行可重復(fù)的單元測(cè)試可以避免產(chǎn)生那些令人不快的負(fù)作用。
不管怎樣, 集成測(cè)試將會(huì)抓住所有的Bug
我們已經(jīng)在前面的討論中從一個(gè)側(cè)面對(duì)這個(gè)問(wèn)題進(jìn)行了部分的闡述。這個(gè)論點(diǎn)不成立的原因在于規(guī)模越大的代碼集成意味著復(fù)雜性就越高。如果軟件的單元沒(méi)有事先進(jìn)行測(cè)試,開(kāi)發(fā)人員很可能會(huì)花費(fèi)大量的時(shí)間僅僅是為了使軟件能夠運(yùn)行,而任何實(shí)際的測(cè)試方案都無(wú)法執(zhí)行。
一旦軟件可以運(yùn)行了,開(kāi)發(fā)人員又要面對(duì)這樣的問(wèn)題:在考慮軟件全局復(fù)雜性的前提下對(duì)每個(gè)單元進(jìn)行全面的測(cè)試。這是一件非常困難的事情,甚至在創(chuàng)造一種單元調(diào)用的測(cè)試條件的時(shí)候,要全面的考慮單元的被調(diào)用時(shí)的各種入口參數(shù)。在軟件集成階段,對(duì)單元功能全面測(cè)試的復(fù)雜程度遠(yuǎn)遠(yuǎn)的超過(guò)獨(dú)立進(jìn)行的單元測(cè)試過(guò)程。
最后的結(jié)果是測(cè)試將無(wú)法達(dá)到它所應(yīng)該有的全面性。一些缺陷將被遺漏,并且很多Bug將被忽略過(guò)去。
讓我們類比一下,假設(shè)我們要清洗一臺(tái)已經(jīng)完全裝配好的食物加工機(jī)器!無(wú)論你噴了多少水和清潔劑,一些食物的小碎片還是會(huì)粘在機(jī)器的死角位置,只有任其腐爛并等待以后再想辦法。但我們換個(gè)角度想想,如果這臺(tái)機(jī)器是拆開(kāi)的, 這些死角也許就不存在或者更容易接觸到了,并且每一部分都可以毫不費(fèi)力的進(jìn)行清洗。
折疊成本效率不高
一個(gè)特定的開(kāi)發(fā)組織或軟件應(yīng)用系統(tǒng)的測(cè)試水平取決于對(duì)那些未發(fā)現(xiàn)的Bug的潛在后果的重視程度。這種后果的嚴(yán)重程度可以從一個(gè)Bug引起的小小的不便到發(fā)生多次的死機(jī)的情況。這種后果可能常常會(huì)被軟件的開(kāi)發(fā)人員所忽視(但是用戶可不會(huì)這樣),這種情況會(huì)長(zhǎng)期的損害這些向用戶提交帶有Bug的軟件的開(kāi)發(fā)組織的信譽(yù),并且會(huì)導(dǎo)致對(duì)未來(lái)的市場(chǎng)產(chǎn)生負(fù)面的影響。相反地,一個(gè)可靠的軟件系統(tǒng)的良好的聲譽(yù)將有助于一個(gè)開(kāi)發(fā)組織獲取未來(lái)的市場(chǎng)。
很多研究成果表明,無(wú)論什么時(shí)候作出修改都要進(jìn)行完整的回歸測(cè)試,在生命周期中盡早地對(duì)軟件產(chǎn)品進(jìn)行測(cè)試將使效率和質(zhì)量得到最好的保證。Bug發(fā)現(xiàn)的越晚,修改它所需的費(fèi)用就越高,因此從經(jīng)濟(jì)角度來(lái)看, 應(yīng)該盡可能早的查找和修改Bug。在修改費(fèi)用變的過(guò)高之前,單元測(cè)試是一個(gè)在早期抓住Bug的機(jī)會(huì)。
相比后階段的測(cè)試,單元測(cè)試的創(chuàng)建更簡(jiǎn)單,維護(hù)更容易,并且可以更方便的進(jìn)行重復(fù)。從全程的費(fèi)用來(lái)考慮, 相比起那些復(fù)雜且曠日持久的集成測(cè)試,或是不穩(wěn)定的軟件系統(tǒng)來(lái)說(shuō),單元測(cè)試所需的費(fèi)用是很低的。
折疊結(jié)論
經(jīng)驗(yàn)表明一個(gè)盡責(zé)的單元測(cè)試方法將會(huì)在軟件開(kāi)發(fā)的某個(gè)階段發(fā)現(xiàn)很多的Bug,并且修改它們的成本也很低。在軟件開(kāi)發(fā)的后期階段,Bug的發(fā)現(xiàn)并修改將會(huì)變得更加困難,并要消耗大量的時(shí)間和開(kāi)發(fā)費(fèi)用。無(wú)論什么時(shí)候作出修改都要進(jìn)行完整的回歸測(cè)試,在生命周期中盡早地對(duì)軟件產(chǎn)品進(jìn)行測(cè)試將使效率和質(zhì)量得到最好的保證。在提供了經(jīng)過(guò)測(cè)試的單元的情況下,系統(tǒng)集成過(guò)程將會(huì)大大地簡(jiǎn)化。開(kāi)發(fā)人員可以將精力集中在單元之間的交互作用和全局的功能實(shí)現(xiàn)上,而不是陷入充滿很多Bug的單元之中不能自拔。
使測(cè)試工作的效力發(fā)揮到最大化的關(guān)鍵在于選擇正確的測(cè)試策略,這其中包含了完全的單元測(cè)試的概念,以及對(duì)測(cè)試過(guò)程的良好的管理,還有適當(dāng)?shù)厥褂孟驛daTEST和Cantata這樣的工具來(lái)支持測(cè)試過(guò)程。這些活動(dòng)可以產(chǎn)生這樣的結(jié)果:在花費(fèi)更低的開(kāi)發(fā)費(fèi)用的情況下得到更穩(wěn)定的軟件。更進(jìn)一步的好處是簡(jiǎn)化了維護(hù)過(guò)程并降低了生命周期的費(fèi)用。有效的單元測(cè)試是推行全局質(zhì)量文化的一部分,而這種質(zhì)量文化將會(huì)為軟件開(kāi)發(fā)者帶來(lái)無(wú)限的商機(jī)。
折疊優(yōu)點(diǎn)一
它是一種驗(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)。
折疊優(yōu)點(diǎn)二
它是一種設(shè)計(jì)行為。
編寫(xiě)單元測(cè)試將使我們從調(diào)用者觀察、思考。特別是先寫(xiě)測(cè)試(test-first),迫使我們把程序設(shè)計(jì)成易于調(diào)用和可測(cè)試的,即迫使我們解除軟件中的耦合。
折疊優(yōu)點(diǎn)三
它是一種編寫(xiě)文檔的行為。
單元測(cè)試是一種無(wú)價(jià)的文檔,它是展示函數(shù)或類如何使用的最佳文檔。這份文檔是可編譯、可運(yùn)行的,并且它保持最新,永遠(yuǎn)與代碼同步。
折疊優(yōu)點(diǎn)四
它具有回歸性。
自動(dòng)化的單元測(cè)試避免了代碼出現(xiàn)回歸,編寫(xiě)完成之后,可以隨時(shí)隨地的快速運(yùn)行測(cè)試。