Test-Driven Development(TDD),是Extreme Programming (XP)--極限編程的一個重要組成部分。
在上面的圖中,列出的的是XP的12個團(tuán)隊實踐。Test-Driven Development是其中之一。
Kent Beck 的著作TDD(Test Driven Development) 中詳細(xì)講述了測試驅(qū)動開發(fā)。
當(dāng)你使用TDD的時候一定要說明是測試驅(qū)動開發(fā)還是測試驅(qū)動設(shè)計。這兩者是有區(qū)別的。測試驅(qū)動開發(fā),是通過測試定義所要開發(fā)的功能的接口,然后實現(xiàn)功能的開發(fā)過程。對于測試驅(qū)動設(shè)計,在XP中似乎已經(jīng)消失了,而是被測試驅(qū)動開發(fā)所取代。另外在XP中有用于描述設(shè)計的,SimpleDesign ,Design Improvement.
一、測試驅(qū)動開發(fā)的基本過程
1) 明確當(dāng)前要完成的功能。可以記錄成一個 TODO 列表。
2) 快速完成針對此功能的測試用例編寫。
3) 測試代碼編譯不通過。
4) 編寫對應(yīng)的功能代碼。
5) 測試通過。
6) 對代碼進(jìn)行重構(gòu),并保證測試通過。
7) 循環(huán)完成所有功能的開發(fā)。
二、測試驅(qū)動開發(fā)的原則
1)測試隔離。不同代碼的測試應(yīng)該相互隔離。對一塊代碼的測試只考慮此代碼的測試,不要考慮其實現(xiàn)細(xì)節(jié)(比如它使用了其他類的邊界條件)。
2)一頂帽子。開發(fā)人員開發(fā)過程中要做不同的工作,比如:編寫測試代碼、開發(fā)功能代碼、對代碼重構(gòu)等。做不同的事,承擔(dān)不同的角色。開發(fā)人員完成對應(yīng)的工作時應(yīng)該保持注意力集中在當(dāng)前工作上,而不要過多的考慮其他方面的細(xì)節(jié),保證頭上只有一頂帽子。避免考慮無關(guān)細(xì)節(jié)過多,無謂地增加復(fù)雜度。
3)測試列表。需要測試的功能點很多。應(yīng)該在任何階段想添加功能需求問題時,把相關(guān)功能點加到測試列表中,然后繼續(xù)手頭工作。然后不斷的完成對應(yīng)的測試用例、功能代碼、重構(gòu)。一是避免疏漏,也避免干擾當(dāng)前進(jìn)行的工作。
4)測試驅(qū)動。這個比較核心。完成某個功能,某個類,首先編寫測試代碼,考慮其如何使用、如何測試。然后在對其進(jìn)行設(shè)計、編碼。
5)先寫斷言。測試代碼編寫時,應(yīng)該首先編寫對功能代碼的判斷用的斷言語句,然后編寫相應(yīng)的輔助語句。
6)可測試性。功能代碼設(shè)計、開發(fā)時應(yīng)該具有較強(qiáng)的可測試性。其實遵循比較好的設(shè)計原則的代碼都具備較好的測試性。比如比較高的內(nèi)聚性,盡量依賴于接口等。
7)及時重構(gòu)。無論是功能代碼還是測試代碼,對結(jié)構(gòu)不合理,重復(fù)的代碼等情況,在測試通過后,及時進(jìn)行重構(gòu)。
三、測試驅(qū)動開發(fā)的測試范圍
按大師 Kent Benk 的話,對那些你認(rèn)為應(yīng)該測試的代碼進(jìn)行測試,測試驅(qū)動開發(fā)強(qiáng)調(diào)測試并不應(yīng)該是負(fù)擔(dān),而應(yīng)該是幫助我們減輕工作量的方法。
四、TDD的優(yōu)點
『充滿吸引力的優(yōu)點』
完工時完工。表明我可以很清楚的看到自己的這段工作已經(jīng)結(jié)束了,而傳統(tǒng)的方式很難知道什么時候編碼工作結(jié)束了。
全面正確的認(rèn)識代碼和利用代碼,而傳統(tǒng)的方式?jīng)]有這個機(jī)會。
為利用你成果的人提供Sample,無論它是要利用你的源代碼,還是直接重用你提供的組件。
開發(fā)小組間降低了交流成本,提高了相互信賴程度。
避免了過渡設(shè)計。
系統(tǒng)可以與詳盡的測試集一起發(fā)布,從而對程序的將來版本的修改和擴(kuò)展提供方便。
TDD給了我們自信,讓我們今天的問題今天解決,明天的問題明天解決,今天不能解決明天的問題,因為明天的問題還沒有出現(xiàn)(沒有TestCase),除非有TestCase否則我決不寫任何代碼;明天也不必?fù)?dān)心今天的問題,只要我亮了綠燈。
『不顯而易見的優(yōu)點』
逃避了設(shè)計角色。對于一個敏捷的開發(fā)小組,每個人都在做設(shè)計。
大部分時間代碼處在高質(zhì)量狀態(tài),100%的時間里成果是可見的。
由于可以保證編寫測試和編寫代碼的是相同的程序員,降低了理解代碼所花費(fèi)的成本。
為減少文檔和代碼之間存在的細(xì)微的差別和由這種差別所引入的Bug作出杰出貢獻(xiàn)。
在預(yù)先設(shè)計和緊急設(shè)計之間建立一種平衡點,為你區(qū)分哪些設(shè)計該事先做、哪些設(shè)計該迭代時做提供了一個可靠的判斷依據(jù)。
『有爭議的優(yōu)點』
事實上提高了開發(fā)效率。每一個正在使用TDD并相信TDD的人都會相信這一點,但觀望者則不同,不相信TDD的人甚至堅決反對這一點,這很正常,世界總是這樣。
發(fā)現(xiàn)比傳統(tǒng)測試方式更多的Bug。
使IDE的調(diào)試功能失去意義,或者應(yīng)該說,避免了令人頭痛的調(diào)試和節(jié)約了調(diào)試的時間。
總是處在要么編程要么重構(gòu)的狀態(tài)下,不會使人抓狂。(兩頂帽子)
單元測試非常有趣。
五、TDD的 優(yōu)勢
TDD的基本思路就是通過測試來推動整個開發(fā)的進(jìn)行。而測試驅(qū)動開發(fā)技術(shù)并不只是單純的測試工作。
需求向來就是軟件開發(fā)過程中感覺最不好明確描述、易變的東西。這里說的需求不只是指用戶的需求,還包括對代碼的使用需求。很多開發(fā)人員最害怕的就是后期還要修改某個類或者函數(shù)的接口進(jìn)行修改或者擴(kuò)展,為什么會發(fā)生這樣的事情就是因為這部分代碼的使用需求沒有很好的描述。測試驅(qū)動開發(fā)就是通過編寫測試用例,先考慮代碼的使用需求(包括功能、過程、接口等),而且這個描述是無二義的,可執(zhí)行驗證的。
通過編寫這部分代碼的測試用例,對其功能的分解、使用過程、接口都進(jìn)行了設(shè)計。而且這種從使用角度對代碼的設(shè)計通常更符合后期開發(fā)的需求??蓽y試的要求,對代碼的內(nèi)聚性的提高和復(fù)用都非常有益。因此測試驅(qū)動開發(fā)也是一種代碼設(shè)計的過程。
開發(fā)人員通常對編寫文檔非常厭煩,但要使用、理解別人的代碼時通常又希望能有文檔進(jìn)行指導(dǎo)。而測試驅(qū)動開發(fā)過程中產(chǎn)生的測試用例代碼就是對代碼的最好的解釋。
快樂工作的基礎(chǔ)就是對自己有信心,對自己的工作成果有信心。當(dāng)前很多開發(fā)人員卻經(jīng)常在擔(dān)心:“代碼是否正確?”“辛苦編寫的代碼還有沒有嚴(yán)重bug?”“修改的新代碼對其他部分有沒有影響?”。這種擔(dān)心甚至導(dǎo)致某些代碼應(yīng)該修改卻不敢修改的地步。測試驅(qū)動開發(fā)提供的測試集就可以作為你信心的來源。
當(dāng)然測試驅(qū)動開發(fā)最重要的功能還在于保障代碼的正確性,能夠迅速發(fā)現(xiàn)、定位bug。而迅速發(fā)現(xiàn)、定位bug是很多開發(fā)人員的夢想。針對關(guān)鍵代碼的測試集,以及不斷完善的測試用例,為迅速發(fā)現(xiàn)、定位bug提供了條件。
我的一段功能非常復(fù)雜的代碼使用TDD開發(fā)完成,真實環(huán)境應(yīng)用中只發(fā)現(xiàn)幾個bug,而且很快被定位解決。您在應(yīng)用后,也一定會為那種自信的開發(fā)過程,功能不斷增加、完善的感覺,迅速發(fā)現(xiàn)、定位bug的能力所感染,喜歡這個技術(shù)的。
那么是什么樣的原理、方法提供上面說的這些好處哪?下面我們就看看TDD的原理。
六、TDD的原理
測試驅(qū)動開發(fā)的基本思想就是在開發(fā)功能代碼之前,先編寫測試代碼。也就是說在明確要開發(fā)某個功能后,首先思考如何對這個功能進(jìn)行測試,并完成測試代碼的編寫,然后編寫相關(guān)的代碼滿足這些測試用例。然后循環(huán)進(jìn)行添加其他功能,直到完全部功能的開發(fā)。
我們這里把這個技術(shù)的應(yīng)用領(lǐng)域從代碼編寫擴(kuò)展到整個開發(fā)過程。應(yīng)該對整個開發(fā)過程的各個階段進(jìn)行測試驅(qū)動,首先思考如何對這個階段進(jìn)行測試、驗證、考核,并編寫相關(guān)的測試文檔,然后開始下一步工作,最后再驗證相關(guān)的工作。下圖是一個比較流行的測試模型:V測試模型。
【圖 V測試模型】
在開發(fā)的各個階段,包括需求分析、概要設(shè)計、詳細(xì)設(shè)計、編碼過程中都應(yīng)該考慮相對應(yīng)的測試工作,完成相關(guān)的測試用例的設(shè)計、測試方案、測試計劃的編寫。這里提到的開發(fā)階段只是舉例,根據(jù)實際的開發(fā)活動進(jìn)行調(diào)整。相關(guān)的測試文檔也不一定是非常詳細(xì)復(fù)雜的文檔,或者什么形式,但應(yīng)該養(yǎng)成測試驅(qū)動的習(xí)慣。
關(guān)于測試模型,還有X測試模型。這個測試模型,我認(rèn)為,是對詳細(xì)階段和編碼階段進(jìn)行建模,應(yīng)該說更詳細(xì)的描述了詳細(xì)設(shè)計和編碼階段的開發(fā)行為。及針對某個功能進(jìn)行對應(yīng)的測試驅(qū)動開發(fā)。
【圖 X測試模型】
基本原理應(yīng)該說非常簡單,那么如何進(jìn)行實際操作哪,下面對開發(fā)過程進(jìn)行詳細(xì)的介紹。
七、測試技術(shù)
1. 測試范圍、粒度
對哪些功能進(jìn)行測試?會不會太繁瑣?什么時候可以停止測試?這些問題比較常見。按大師 Kent Benk 的話,對那些你認(rèn)為應(yīng)該測試的代碼進(jìn)行測試。就是說,要相信自己的感覺,自己的經(jīng)驗。那些重要的功能、核心的代碼就應(yīng)該重點測試。感到疲勞就應(yīng)該停下來休息一下。感覺沒有必要更詳細(xì)的測試,就停止本輪測試。
測試驅(qū)動開發(fā)強(qiáng)調(diào)測試并不應(yīng)該是負(fù)擔(dān),而應(yīng)該是幫助我們減輕工作量的方法。而對于何時停止編寫測試用例,也是應(yīng)該根據(jù)你的經(jīng)驗,功能復(fù)雜、核心功能的代碼就應(yīng)該編寫更全面、細(xì)致的測試用例,否則測試流程即可。
測試范圍沒有靜態(tài)的標(biāo)準(zhǔn),同時也應(yīng)該可以隨著時間改變。對于開始沒有編寫足夠的測試的功能代碼,隨著bug的出現(xiàn),根據(jù)bug補(bǔ)齊相關(guān)的測試用例即可。
小步前進(jìn)的原則,要求我們對大的功能塊測試時,應(yīng)該先分拆成更小的功能塊進(jìn)行測試,比如一個類A使用了類B、C,就應(yīng)該編寫到A使用B、C功能的測試代碼前,完成對B、C的測試和開發(fā)。那么是不是每個小類或者小函數(shù)都應(yīng)該測試哪?我認(rèn)為沒有必要。你應(yīng)該運(yùn)用你的經(jīng)驗,對那些可能出問題的地方重點測試,感覺不可能出問題的地方就等它真正出問題的時候再補(bǔ)測試吧。
2. 怎么編寫測試用例
測試用例的編寫就用上了傳統(tǒng)的測試技術(shù)。
操作過程盡量模擬正常使用的過程。
全面的測試用例應(yīng)該盡量做到分支覆蓋,核心代碼盡量做到路徑覆蓋。
測試數(shù)據(jù)盡量包括:真實數(shù)據(jù)、邊界數(shù)據(jù)。
測試語句和測試數(shù)據(jù)應(yīng)該盡量簡單,容易理解。
為了避免對其他代碼過多的依賴,可以實現(xiàn)簡單的樁函數(shù)或樁類(Mock Object)。
如果內(nèi)部狀態(tài)非常復(fù)雜或者應(yīng)該判斷流程而不是狀態(tài),可以通過記錄日志字符串的方式進(jìn)行驗證。
八、Tips
很多朋友有疑問,“測試代碼的正確性如何保障?是寫測試代碼還是寫測試文檔?”這樣是不是會陷入“雞生蛋,蛋生雞”的循環(huán)。其實是不會的。通常測試代碼通常是非常簡單的,通常圍繞著某個情況的正確性判斷的幾個語句,如果太復(fù)雜,就應(yīng)該繼續(xù)分解啦。而傳統(tǒng)的開發(fā)過程通常強(qiáng)調(diào)測試文檔。但隨著開發(fā)節(jié)奏的加快,用戶需求的不斷變化,維護(hù)高層(需求、概要設(shè)計)的測試文檔可以,更低層的測試文檔的成本的確太大了。而且可實時驗證功能正確性的測試代碼就是對代碼最好的文檔。
軟件開發(fā)過程中,除了遵守上面提到的測試驅(qū)動開發(fā)的幾個原則外,一個需要注意的問題就是,謹(jǐn)防過度設(shè)計。編寫功能代碼時應(yīng)該關(guān)注于完成當(dāng)前功能點,通過測試,使用最簡單、直接的方式來編碼。過多的考慮后期的擴(kuò)展,其他功能的添加,無疑增加了過多的復(fù)雜性,容易產(chǎn)生問題。應(yīng)該等到要添加這些特性時在進(jìn)行詳細(xì)的測試驅(qū)動開發(fā)。到時候,有整套測試用例做基礎(chǔ),通過不斷重構(gòu)很容易添加相關(guān)特性。
九、FAQ
[什么時候重構(gòu)?]
如果您在軟件公司工作,就意味著您成天都會和想通過重構(gòu)改善代碼質(zhì)量的想法打交道,不僅您如此,您的大部分同事也都如此??墒牵烤故裁磿r候該重構(gòu),什么情況下應(yīng)該重構(gòu)呢?我相信您和您的同事可能有很多不同的看法,最常見的答案是“該重構(gòu)時重構(gòu)”,“寫不下去的時候重構(gòu)”,和“下一次迭代開始之前重構(gòu)”,或者干脆就是“最近沒時間,就不重構(gòu)了,下次有時間的時候重構(gòu)吧”。正如您已經(jīng)預(yù)見到我想說的——這些想法都是對重構(gòu)的誤解。重構(gòu)不是一種構(gòu)建軟件的工具,不是一種設(shè)計軟件的模式,也不是一個軟件開發(fā)過程中的環(huán)節(jié),正確理解重構(gòu)的人應(yīng)該把重構(gòu)看成一種書寫代碼的方式,或習(xí)慣,重構(gòu)時時刻刻有可能發(fā)生。在TDD中,除去編寫測試用例和實現(xiàn)測試用例之外的所有工作都是重構(gòu),所以,沒有重構(gòu)任何設(shè)計都不能實現(xiàn)。至于什么時候重構(gòu)嘛,還要分開看,有三句話是我的經(jīng)驗:實現(xiàn)測試用例時重構(gòu)代碼,完成某個特性時重構(gòu)設(shè)計,產(chǎn)品的重構(gòu)完成后還要記得重構(gòu)一下測試用例哦。
[什么時候設(shè)計?]
這個問題比前面一個要難回答的多,實話實說,本人在依照TDD開發(fā)軟件的時候也常常被這個問題困擾,總是覺得有些問題應(yīng)該在寫測試用例之前定下來,而有些問題應(yīng)該在新增一個一個測試用例的過程中自然出現(xiàn),水到渠成。所以,我的建議是,設(shè)計的時機(jī)應(yīng)該由開發(fā)者自己把握,不要受到TDD方式的限制,但是,不需要事先確定的事一定不能事先確定,免得捆住了自己的手腳。
[什么時候增加新的TestCase?]
沒事做的時候。通常我們認(rèn)為,如果你要增加一個新的功能,那么先寫一個不能通過的TestCase;如果你發(fā)現(xiàn)了一個bug,那么先寫一個不能通過的TestCase;如果你現(xiàn)在什么都沒有,從0開始,請先寫一個不能通過的TestCase。所有的工作都是從一個TestCase開始。此外,還要注意的是,一些大師要求我們每次只允許有一個TestCase亮紅燈,在這個TestCase沒有Green之前不可以寫別的TestCase,這種要求可以適當(dāng)考慮,但即使有多個TestCase亮紅燈也不要緊,并未違反TDD的主要精神。
[TestCase該怎么寫?]
測試用例的編寫實際上就是兩個過程:使用尚不存在的代碼和定義這些代碼的執(zhí)行結(jié)果。所以一個TestCase也就應(yīng)該包括兩個部分——場景和斷言。第一次寫TestCase的人會有很大的不適應(yīng)的感覺,因為你之前所寫的所有東西都是在解決問題,現(xiàn)在要你提出問題確實不大習(xí)慣,不過不用擔(dān)心,你正在做正確的事情,而這個世界上最難的事情也不在于如何解決問題,而在于ask the right question!
[TDD能幫助我消除Bug嗎?]
答:不能!千萬不要把“測試”和“除蟲”混為一談!“除蟲”是指程序員通過自己的努力來減少bug的數(shù)量(消除bug這樣的字眼我們還是不要講為好^_^),而“測試”是指程序員書寫產(chǎn)品以外的一段代碼來確保產(chǎn)品能有效工作。雖然TDD所編寫的測試用例在一定程度上為尋找bug提供了依據(jù),但事實上,按照TDD的方式進(jìn)行的軟件開發(fā)是不可能通過TDD再找到bug的(想想我們前面說的“完工時完工”),你想啊,當(dāng)我們的代碼完成的時候,所有的測試用例都亮了綠燈,這時隱藏在代碼中的bug一個都不會露出馬腳來。
但是,如果要問“測試”和“除蟲”之間有什么聯(lián)系,我相信還是有很多話可以講的,比如TDD事實上減少了bug的數(shù)量,把查找bug戰(zhàn)役的關(guān)注點從全線戰(zhàn)場提升到代碼戰(zhàn)場以上。還有,bug的最可怕之處不在于隱藏之深,而在于滿天遍野。如果你發(fā)現(xiàn)了一個用戶很不容易才能發(fā)現(xiàn)的bug,那么不一定對工作做出了什么杰出貢獻(xiàn),但是如果你發(fā)現(xiàn)一段代碼中,bug的密度或離散程度過高,那么恭喜你,你應(yīng)該拋棄并重寫這段代碼了。TDD避免了這種情況,所以將尋找bug的工作降低到了一個新的低度。
[我該為一個Feature編寫TestCase還是為一個類編寫TestCase?]
初學(xué)者常問的問題。雖然我們從TDD的說明書上看到應(yīng)該為一個特性編寫相應(yīng)的TestCase,但為什么著名的TDD大師所寫的TestCase都是和類/方法一一對應(yīng)的呢?為了解釋這個問題,我和我的同事們都做了很多試驗,最后我們得到了一個結(jié)論,雖然我不知道是否正確,但是如果您沒有答案,可以姑且相信我們。
我們的研究結(jié)果表明,通常在一個特性的開發(fā)開始時,我們針對特性編寫測試用例,如果您發(fā)現(xiàn)這個特性無法用TestCase表達(dá),那么請將這個特性細(xì)分,直至您可以為手上的特性寫出TestCase為止。從這里開始是最安全的,它不會導(dǎo)致任何設(shè)計上重大的失誤。但是,隨著您不斷的重構(gòu)代碼,不斷的重構(gòu)TestCase,不斷的依據(jù)TDD的思想做下去,最后當(dāng)產(chǎn)品伴隨測試用例集一起發(fā)布的時候,您就會不經(jīng)意的發(fā)現(xiàn)經(jīng)過重構(gòu)以后的測試用例很可能是和產(chǎn)品中的類/方法一一對應(yīng)的。
[什么時候應(yīng)該將全部測試都運(yùn)行一遍?]
Good Question!大師們要求我們每次重構(gòu)之后都要完整的運(yùn)行一遍測試用例。這個要求可以理解,因為重構(gòu)很可能會改變整個代碼的結(jié)構(gòu)或設(shè)計,從而導(dǎo)致不可預(yù)見的后果,但是如果我正在開發(fā)的是一個ERP怎么辦?運(yùn)行一遍完整的測試用例可能將花費(fèi)數(shù)個小時,況且現(xiàn)在很多重構(gòu)都是由工具做到的,這個要求的可行性和前提條件都有所動搖。所以我認(rèn)為原則上你可以挑幾個你覺得可能受到本次重構(gòu)影響的TestCase去run,但是如果運(yùn)行整個測試包只要花費(fèi)數(shù)秒的時間,那么不介意你按大師的要求去做。
[什么時候改進(jìn)一個TestCase?]
增加的測試用例或重構(gòu)以后的代碼導(dǎo)致了原來的TestCase的失去了效果,變得無意義,甚至可能導(dǎo)致錯誤的結(jié)果,這時是改進(jìn)TestCase的最好時機(jī)。但是有時你會發(fā)現(xiàn),這樣做僅僅導(dǎo)致了原來的TestCase在設(shè)計上是臃腫的,或者是冗余的,這都不要緊,只要它沒有失效,你仍然不用去改進(jìn)它。記住,TestCase不是你的產(chǎn)品,它不要好看,也不要怎么太科學(xué),甚至沒有性能要求,它只要能完成它的使命就可以了——這也證明了我們后面所說的“用Ctrl-C/Ctrl-V編寫測試用例”的可行性。
但是,美國人的想法其實跟我們還是不太一樣,拿托尼巴贊的MindMap來說吧,其實畫MindMap只是為了表現(xiàn)自己的思路,或記憶某些重要的事情,但托尼卻建議大家把MindMap畫成一件藝術(shù)品,甚至還有很多藝術(shù)家把自己畫的抽象派MindMap拿出來幫助托尼做宣傳。同樣,大師們也要求我們把TestCase寫的跟代碼一樣質(zhì)量精良,可我想說的是,現(xiàn)在國內(nèi)有幾個公司能把產(chǎn)品的代碼寫的精良??還是一步一步慢慢來吧。
[為什么原來通過的測試用例現(xiàn)在不能通過了?]
這是一個警報,Red Alert!它可能表達(dá)了兩層意思——都不是什么好意思——1)你剛剛進(jìn)行的重構(gòu)可能失敗了,或存在一些錯誤未被發(fā)現(xiàn),至少重構(gòu)的結(jié)果和原來的代碼不等價了。2)你剛剛增加的TestCase所表達(dá)的意思跟前面已經(jīng)有的TestCase相沖突,也就是說,新增的功能違背了已有的設(shè)計,這種情況大部分可能是之前的設(shè)計錯了。但無論哪錯了,無論是那層意思,想找到這個問題的根源都比TDD的正常工作要難。
[我怎么知道那里該有一個方法還是該有一個類?]
這個問題也是常常出現(xiàn)在我的腦海中,無論你是第一次接觸TDD或者已經(jīng)成為TDD專家,這個問題都會纏繞著你不放。不過問題的答案可以參考前面的“什么時候設(shè)計”一節(jié),答案不是唯一的。其實多數(shù)時候你不必考慮未來,今天只做今天的事,只要有重構(gòu)工具,從方法到類和從類到方法都很容易。
[我要寫一個TestCase,可是不知道從哪里開始?]
從最重要的事開始,what matters most?從腳下開始,從手頭上的工作開始,從眼前的事開始。從一個沒有UI的核心特性開始,從算法開始,或者從最有可能耽誤時間的模塊開始,從一個最嚴(yán)重的bug開始。這是TDD主義者和鼠目寸光者的一個共同點,不同點是前者早已成竹在胸。
[為什么我的測試總是看起來有點愚蠢?]
哦?是嗎?來,握個手,我的也是!不必?fù)?dān)心這一點,事實上,大師們給的例子也相當(dāng)愚蠢,比如一個極端的例子是要寫一個兩個int變量相加的方法,大師先斷言2+3=5,再斷言5+5=10,難道這些代碼不是很愚蠢嗎?其實這只是一個極端的例子,當(dāng)你初次接觸TDD時,寫這樣的代碼沒什么不好,以后當(dāng)你熟練時就會發(fā)現(xiàn)這樣寫沒必要了,要記住,謙虛是通往TDD的必經(jīng)之路!從經(jīng)典開發(fā)方法轉(zhuǎn)向TDD就像從面向過程轉(zhuǎn)向面向?qū)ο?/a>一樣困難,你可能什么都懂,但你寫出來的類沒有一個純OO的!我的同事還告訴我真正的太極拳,其速度是很快的,不比任何一個快拳要慢,但是初學(xué)者(通常是指學(xué)習(xí)太極拳的前10年)太不容易把每個姿勢都做對,所以只能慢慢來。
[什么場合不適用TDD?]
問的好,確實有很多場合不適合使用TDD。比如對軟件質(zhì)量要求極高的軍事或科研產(chǎn)品——神州六號,人命關(guān)天的軟件——醫(yī)療設(shè)備,等等,再比如設(shè)計很重要必須提前做好的軟件,這些都不適合TDD,但是不適合TDD不代表不能寫TestCase,只是作用不同,地位不同罷了