TDD的基本思路就是經過測試來推進整個開發的進行。而測試驅動開發技術並不僅是單純的測試工做。html
需求向來就是軟件開發過程當中感受最很差明確描述、易變的東西。這裏說的需求不僅是指用戶的需求,還包括對代碼的使用需求。不少開發人員最懼怕的就是後期還要修改某個類或者函數的接口進行修改或者擴展,爲何會發生這樣的事情就是由於這部分代碼的使用需求沒有很好的描述。測試驅動開發就是經過編寫測試用例,先考慮代碼的使用需求(包括功能、過程、接口等),並且這個描述是無二義的,可執行驗證的。linux
經過編寫這部分代碼的測試用例,對其功能的分解、使用過程、接口都進行了設計。並且這種從使用角度對代碼的設計一般更符合後期開發的需求。可測試的要求,對代碼的內聚性的提升和複用都很是有益。所以測試驅動開發也是一種代碼設計的過程。編程
開發人員一般對編寫文檔很是厭煩,但要使用、理解別人的代碼時一般又但願能有文檔進行指導。而測試驅動開發過程當中產生的測試用例代碼就是對代碼的最好的解釋。框架
快樂工做的基礎就是對本身有信心,對本身的工做成果有信心。當前不少開發人員卻常常在擔憂:「代碼是否正確?」「辛苦編寫的代碼還有沒有嚴重bug?」「修改的新代碼對其餘部分有沒有影響?」。這種擔憂甚至致使某些代碼應該修改卻不敢修改的地步。測試驅動開發提供的測試集就能夠做爲你信心的來源。函數
固然測試驅動開發最重要的功能還在於保障代碼的正確性,可以迅速發現、定位bug。而迅速發現、定位bug是不少開發人員的夢想。針對關鍵代碼的測試集,以及不斷完善的測試用例,爲迅速發現、定位bug提供了條件。工具
個人一段功能很是複雜的代碼使用TDD開發完成,真實環境應用中只發現幾個bug,並且很快被定位解決。您在應用後,也必定會爲那種自信的開發過程,功能不斷增長、完善的感受,迅速發現、定位bug的能力所感染,喜歡這個技術的。post
那麼是什麼樣的原理、方法提供上面說的這些好處哪?下面咱們就看看TDD的原理。性能
回頁首開發工具
測試驅動開發的基本思想就是在開發功能代碼以前,先編寫測試代碼。也就是說在明確要開發某個功能後,首先思考如何對這個功能進行測試,並完成測試代碼的編寫,而後編寫相關的代碼知足這些測試用例。而後循環進行添加其餘功能,直到徹底部功能的開發。測試
咱們這裏把這個技術的應用領域從代碼編寫擴展到整個開發過程。應該對整個開發過程的各個階段進行測試驅動,首先思考如何對這個階段進行測試、驗證、考覈,並編寫相關的測試文檔,而後開始下一步工做,最後再驗證相關的工做。下圖是一個比較流行的測試模型:V測試模型。
在開發的各個階段,包括需求分析、概要設計、詳細設計、編碼過程當中都應該考慮相對應的測試工做,完成相關的測試用例的設計、測試方案、測試計劃的編寫。這裏提到的開發階段只是舉例,根據實際的開發活動進行調整。相關的測試文檔也不必定是很是詳細複雜的文檔,或者什麼形式,但應該養成測試驅動的習慣。
關於測試模型,還有X測試模型。這個測試模型,我認爲,是對詳細階段和編碼階段進行建模,應該說更詳細的描述了詳細設計和編碼階段的開發行爲。及針對某個功能進行對應的測試驅動開發。
基本原理應該說很是簡單,那麼如何進行實際操做哪,下面對開發過程進行詳細的介紹。
軟件開發其餘階段的測試驅動開發,根據測試驅動開發的思想完成對應的測試文檔便可。下面針對詳細設計和編碼階段進行介紹。
測試驅動開發的基本過程以下:
1) 明確當前要完成的功能。能夠記錄成一個 TODO 列表。
2) 快速完成針對此功能的測試用例編寫。
3) 測試代碼編譯不經過。
4) 編寫對應的功能代碼。
5) 測試經過。
6) 對代碼進行重構,並保證測試經過。
7) 循環完成全部功能的開發。
爲了保證整個測試過程比較快捷、方便,一般可使用測試框架組織全部的測試用例。一個免費的、優秀的測試框架是 Xunit 系列,幾乎全部的語言都有對應的測試框架。我曾經寫過一篇文章介紹CppUnit的文章( http://www.ibm.com/developerworks/cn/linux/l-cppunit/index.html)。
開發過程當中,一般把測試代碼和功能代碼分開存放,這裏提供一個簡單的測試框架使用例子,您能夠經過它瞭解測試框架的使用。下面是文件列表。
project/ 項目主目錄 project/test 測試項目主目錄 project/test/testSeq.cpp 測試seq_t 的測試文件,對其餘功能文件的測試文件複製後修改便可 project/test/testSeq.h project/test/Makefile 測試項目的 Makefile project/test/main.cpp 測試項目的主文件,不須要修改 project/main.cpp 項目的主文件 project/seq_t.h 功能代碼,被測試文件 project/Makefile 項目的 Makefile
主要流程基本如此,但要讓你的代碼很容易的進行測試,全面又不繁瑣的進行測試,仍是有不少測試原則和技術須要考慮。
測試隔離。不一樣代碼的測試應該相互隔離。對一塊代碼的測試只考慮此代碼的測試,不要考慮其實現細節(好比它使用了其餘類的邊界條件)。
一頂帽子。開發人員開發過程當中要作不一樣的工做,好比:編寫測試代碼、開發功能代碼、對代碼重構等。作不一樣的事,承擔不一樣的角色。開發人員完成對應的工做時應該保持注意力集中在當前工做上,而不要過多的考慮其餘方面的細節,保證頭上只有一頂帽子。避免考慮無關細節過多,無謂地增長複雜度。
測試列表。須要測試的功能點不少。應該在任何階段想添加功能需求問題時,把相關功能點加到測試列表中,而後繼續手頭工做。而後不斷的完成對應的測試用例、功能代碼、重構。一是避免疏漏,也避免干擾當前進行的工做。
測試驅動。這個比較核心。完成某個功能,某個類,首先編寫測試代碼,考慮其如何使用、如何測試。而後在對其進行設計、編碼。
先寫斷言。測試代碼編寫時,應該首先編寫對功能代碼的判斷用的斷言語句,而後編寫相應的輔助語句。
可測試性。功能代碼設計、開發時應該具備較強的可測試性。其實遵循比較好的設計原則的代碼都具有較好的測試性。好比比較高的內聚性,儘可能依賴於接口等。
及時重構。不管是功能代碼仍是測試代碼,對結構不合理,重複的代碼等狀況,在測試經過後,及時進行重構。關於重構,我會另撰文詳細分析。
小步前進。軟件開發是個複雜性很是高的工做,開發過程當中要考慮不少東西,包括代碼的正確性、可擴展性、性能等等,不少問題都是由於複雜性太大致使的。極限編程提出了一個很是好的思路就是小步前進。把全部的規模大、複雜性高的工做,分解成小的任務來完成。對於一個類來講,一個功能一個功能的完成,若是太困難就再分解。每一個功能的完成就走測試代碼-功能代碼-測試-重構的循環。經過分解下降整個系統開發的複雜性。這樣的效果很是明顯。幾個小的功能代碼完成後,大的功能代碼幾乎是不用調試就能夠經過。一個個類方法的實現,很快就看到整個類很快就完成啦。原本感受不少特性須要增長,很快就會看到沒有幾個啦。你甚至會爲這個速度感到震驚。(我理解,是大幅度減小調試、出錯的時間產生的這種速度感)
對哪些功能進行測試?會不會太繁瑣?何時能夠中止測試?這些問題比較常見。按大師 Kent Benk 的話,對那些你認爲應該測試的代碼進行測試。就是說,要相信本身的感受,本身的經驗。那些重要的功能、核心的代碼就應該重點測試。感到疲勞就應該停下來休息一下。感受沒有必要更詳細的測試,就中止本輪測試。
測試驅動開發強調測試並不該該是負擔,而應該是幫助咱們減輕工做量的方法。而對於什麼時候中止編寫測試用例,也是應該根據你的經驗,功能複雜、核心功能的代碼就應該編寫更全面、細緻的測試用例,不然測試流程便可。
測試範圍沒有靜態的標準,同時也應該能夠隨着時間改變。對於開始沒有編寫足夠的測試的功能代碼,隨着bug的出現,根據bug補齊相關的測試用例便可。
小步前進的原則,要求咱們對大的功能塊測試時,應該先分拆成更小的功能塊進行測試,好比一個類A使用了類B、C,就應該編寫到A使用B、C功能的測試代碼前,完成對B、C的測試和開發。那麼是否是每一個小類或者小函數都應該測試哪?我認爲沒有必要。你應該運用你的經驗,對那些可能出問題的地方重點測試,感受不可能出問題的地方就等它真正出問題的時候再補測試吧。
測試用例的編寫就用上了傳統的測試技術。
不少朋友有疑問,「測試代碼的正確性如何保障?是寫測試代碼仍是寫測試文檔?」這樣是否是會陷入「雞生蛋,蛋生雞」的循環。實際上是不會的。一般測試代碼一般是很是簡單的,一般圍繞着某個狀況的正確性判斷的幾個語句,若是太複雜,就應該繼續分解啦。而傳統的開發過程一般強調測試文檔。但隨着開發節奏的加快,用戶需求的不斷變化,維護高層(需求、概要設計)的測試文檔能夠,更低層的測試文檔的成本的確太大了。並且可實時驗證功能正確性的測試代碼就是對代碼最好的文檔。
軟件開發過程當中,除了遵照上面提到的測試驅動開發的幾個原則外,一個須要注意的問題就是,謹防過分設計。編寫功能代碼時應該關注於完成當前功能點,經過測試,使用最簡單、直接的方式來編碼。過多的考慮後期的擴展,其餘功能的添加,無疑增長了過多的複雜性,容易產生問題。應該等到要添加這些特性時在進行詳細的測試驅動開發。到時候,有整套測試用例作基礎,經過不斷重構很容易添加相關特性。