測試驅動開發

2021-08-30 20:54:25 字數 4957 閱讀 7368

測試驅動開發:

背景乙個 高效的軟體開發過程對軟體開發人員來說是至關重要的,決定著開發是痛苦的掙扎,還是不斷進步的喜悅。國人對軟體藍領的不屑,對繁瑣冗長的傳統開發過程的不 耐,使大多數開發人員無所適從。最近興起的一些軟體開發過程相關的技術,提供一些比較高效、實用的軟體過程開發方法。其中比較基礎、關鍵的乙個技術就是測 試驅動開發(test-driven development)。雖然tdd光大於極限程式設計,但測試驅動開發完全可以單獨應用。下面就從開發人員使用的角度進行介紹,使開發人員用最少的代價盡 快理解、掌握、應用這種技術。下面分優勢,原理,過程,原則,測試技術,tips等方面進行討論。

1. 優勢

tdd的基本思路就是通過測試來推動整個開發的進行。而測試驅動開發技術並不只是單純的測試工作。

需 求向來就是軟體開發過程中感覺最不好明確描述、易變的東西。這裡說的需求不只是指使用者的需求,還包括對**的使用需求。很多開發人員最害怕的就是後期還要 修改某個類或者函式的介面進行修改或者擴充套件,為什麼會發生這樣的事情就是因為這部分**的使用需求沒有很好的描述。測試驅動開發就是通過編寫測試用例,先 考慮**的使用需求(包括功能、過程、介面等),而且這個描述是無二義的,可執行驗證的。

通過編寫這部分**的測試用例,對其功能的分解、使用過程、介面都進行了設計。而且這種從使用角度對**的設計通常更符合後期開發的需求。可測試的要求,對**的內聚性的提高和復用都非常有益。因此測試驅動開發也是一種**設計的過程。

開發人員通常對編寫文件非常厭煩,但要使用、理解別人的**時通常又希望能有文件進行指導。而測試驅動開發過程中產生的測試用例**就是對**的最好的解釋。

快 樂工作的基礎就是對自己有信心,對自己的工作成果有信心。當前很多開發人員卻經常在擔心:「**是否正確?」「辛苦編寫的**還有沒有嚴重bug?」「修 改的新**對其他部分有沒有影響?」。這種擔心甚至導致某些**應該修改卻不敢修改的地步。測試驅動開發提供的測試集就可以作為你信心的**。

當然測試驅動開發最重要的功能還在於保障**的正確性,能夠迅速發現、定位bug。而迅速發現、定位bug是很多開發人員的夢想。針對關鍵**的測試集,以及不斷完善的測試用例,為迅速發現、定位bug提供了條件。

我的一段功能非常複雜的**使用tdd開發完成,真實環境應用中只發現幾個bug,而且很快被定位解決。您在應用後,也一定會為那種自信的開發過程,功能不斷增加、完善的感覺,迅速發現、定位bug的能力所感染,喜歡這個技術的。

那麼是什麼樣的原理、方法提供上面說的這些好處哪?下面我們就看看tdd的原理。

2. 原理

測試驅動開發的基本思想就是在開發功能**之前,先編寫測試**。也就是說在明確要開發某個功能後,首先思考如何對這個功能進行測試,並完成測試**的編寫,然後編寫相關的**滿足這些測試用例。然後迴圈進行新增其他功能,直到完全部功能的開發。

我們這裡把這個技術的應用領域從**編寫擴充套件到整個開發過程。應該對整個開發過程的各個階段進行測試驅動,首先思考如何對這個階段進行測試、驗證、考核,並編寫相關的測試文件,然後開始下一步工作,最後再驗證相關的工作。下圖是乙個比較流行的測試模型:v測試模型。

【圖 v測試模型】

【圖 v測試模型】

在 開發的各個階段,包括需求分析、概要設計、詳細設計、編碼過程中都應該考慮相對應的測試工作,完成相關的測試用例的設計、測試方案、測試計畫的編寫。這裡 提到的開發階段只是舉例,根據實際的開發活動進行調整。相關的測試文件也不一定是非常詳細複雜的文件,或者什麼形式,但應該養成測試驅動的習慣。

關於測試模型,還有x測試模型。這個測試模型,我認為,是對詳細階段和編碼階段進行建模,應該說更詳細的描述了詳細設計和編碼階段的開發行為。及針對某個功能進行對應的測試驅動開發。

【圖 x測試模型】

【圖 x測試模型】

基本原理應該說非常簡單,那麼如何進行實際操作哪,下面對開發過程進行詳細的介紹。

3. 過程

軟體開發其他階段的測試驅動開發,根據測試驅動開發的思想完成對應的測試文件即可。下面針對詳細設計和編碼階段進行介紹。

測試驅動開發的基本過程如下:

1) 明確當前要完成的功能。可以記錄成乙個 todo 列表。

2) 快速完成針對此功能的測試用例編寫。

3) 測試**編譯不通過。

4) 編寫對應的功能**。

5) 測試通過。

6) 對**進行重構,並保證測試通過。

7) 迴圈完成所有功能的開發。

為了保證整個測試過程比較快捷、方便,通常可以使用測試框架組織所有的測試用例。乙個免費的、優秀的測試框架是 xunit 系列,幾乎所有的語言都有對應的測試框架。我曾經寫過一篇文章介紹cppunit的文章。

開發過程中,通常把測試**和功能**分開存放,這裡提供乙個簡單的測試框架使用例子,您可以通過它了解測試框架的使用。下面是檔案列表。

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

主要流程基本如此,但要讓你的**很容易的進行測試,全面又不繁瑣的進行測試,還是有很多測試原則和技術需要考慮。

4. 原則

測試隔離。

不同**的測試應該相互隔離。對一塊**的測試只考慮此**的測試,不要考慮其實現細節(比如它使用了其他類的邊界條件)。

一頂帽子。

開發人員開發過程中要做不同的工作,比如:編寫測試**、開發功能**、對**重構等。做不同的事, 承擔不同的角色。開發人員完成對應的工作時應該保持注意力集中在當前工作上,而不要過多的考慮其他方面的細節,保證頭上只有一頂帽子。避免考慮無關細節過 多,無謂地增加複雜度。

測試列表。

需要測試的功能點很多。應該在任何階段想新增功能需求問題時,把相關功能點加到測試列表中,然後繼續手頭工作。然後不斷的完成對應的測試用例、功能**、重構。一是避免疏漏,也避免干擾當前進行的工作。

測試驅動。

這個比較核心。完成某個功能,某個類,首先編寫測試**,考慮其如何使用、如何測試。然後在對其進行設計、編碼。

先寫斷言。測試**編寫時,應該首先編寫對功能**的判斷用的斷言語句,然後編寫相應的輔助語句。

可測試性。功能**設計、開發時應該具有較強的可測試性。其實遵循比較好的設計原則的**都具備較好的測試性。比如比較高的內聚性,盡量依賴於介面等。

及時重構。

無論是功能**還是測試**,對結構不合理,重複的**等情況,在測試通過後,及時進行重構。關於重構,我會另撰文詳細分析。

小步前進。

軟體開發是個複雜性非常高的工作,開發過程中要考慮很多東西,包括**的正確性、可擴充套件性、效能等等,很多問題都是因為複雜性太大導致的。極限編 程提出了乙個非常好的思路就是小步前進。把所有的規模大、複雜性高的工作,分解成小的任務來完成。對於乙個類來說,乙個功能乙個功能的完成,如果太困難就 再分解。每個功能的完成就走測試**-功能**-測試-重構的迴圈。通過分解降低整個系統開發的複雜性。這樣的效果非常明顯。幾個小的功能**完成後,大 的功能**幾乎是不用除錯就可以通過。乙個個類方法的實現,很快就看到整個類很快就完成啦。本來感覺很多特性需要增加,很快就會看到沒有幾個啦。你甚至會 為這個速度感到震驚。(我理解,是大幅度減少除錯、出錯的時間產生的這種速度感)

5. 測試技術

5.1. 測試範圍、粒度

對 哪些功能進行測試?會不會太繁瑣?什麼時候可以停止測試?這些問題比較常見。按大師 kent benk 的話,對那些你認為應該測試的**進行測試。就是說,要相信自己的感覺,自己的經驗。那些重要的功能、核心的**就應該重點測試。感到疲勞就應該停下來休 息一下。感覺沒有必要更詳細的測試,就停止本輪測試。

測試驅動開發強調測試並不應該是負擔,而應該是幫助我們減輕工作量的方法。而對於何時停止編寫測試用例,也是應該根據你的經驗,功能複雜、核心功能的**就應該編寫更全面、細緻的測試用例,否則測試流程即可。

測試範圍沒有靜態的標準,同時也應該可以隨著時間改變。對於開始沒有編寫足夠的測試的功能**,隨著bug的出現,根據bug補齊相關的測試用例即可。

小步前進的原則,要求我們對大的功能塊測試時,應該先分拆成更小的功能塊進行測試,比如乙個類a使用了類b、c,就應該編寫到a使用b、c功能的測試** 前,完成對b、c的測試和開發。那麼是不是每個小類或者小函式都應該測試哪?我認為沒有必要。你應該運用你的經驗,對那些可能出問題的地方重點測試,感覺 不可能出問題的地方就等它真正出問題的時候再補測試吧。

5.2. 怎麼編寫測試用例

測試用例的編寫就用上了傳統的測試技術。

* 操作過程盡量模擬正常使用的過程。

* 全面的測試用例應該盡量做到分支覆蓋,核心**盡量做到路徑覆蓋。

* 測試資料盡量包括:真實資料、邊界資料。

* 測試語句和測試資料應該盡量簡單,容易理解。

* 為了避免對其他**過多的依賴,可以實現簡單的樁函式或樁類(mock object)。

* 如果內部狀態非常複雜或者應該判斷流程而不是狀態,可以通過記錄日誌字串的方式進行驗證。

6. tips

很 多朋友有疑問,「測試**的正確性如何保障?是寫測試**還是寫測試文件?」這樣是不是會陷入「雞生蛋,蛋生雞」的迴圈。其實是不會的。通常測試**通常 是非常簡單的,通常圍繞著某個情況的正確性判斷的幾個語句,如果太複雜,就應該繼續分解啦。而傳統的開發過程通常強調測試文件。但隨著開發節奏的加快,用 戶需求的不斷變化,維護高層(需求、概要設計)的測試文件可以,更低層的測試文件的成本的確太大了。而且可實時驗證功能正確性的測試**就是對**最好的 文件。

軟體開發過程中,除了遵守上面提到的測試驅動開發的幾個原則外,乙個需要注意的問題就是,謹防過度設計。 編寫功能**時應該關注於完成當前功能點,通過測試,使用最簡單、直接的方式來編碼。過多的考慮後期的擴充套件,其他功能的新增,無疑增加了過多的複雜性,容 易產生問題。應該等到要新增這些特性時在進行詳細的測試驅動開發。到時候,有整套測試用例做基礎,通過不斷重構很容易新增相關特性。

測試驅動開發

測試驅動開發 test driven development,英文縮寫tdd 是極限程式設計的乙個重要組成部分,它的基本思想就是在開發功能 之前,先編寫測試 也就是說在明確要開發某個功能後,首先思考如何對這個功能進行測試,並完成測試 的編寫,然後編寫相關的 滿足這些測試用例。然後迴圈進行新增其他功能...

測試驅動開發

在開發的過程中,總有種憂慮感,擔心系統會出現這樣或那樣的bug,修改bug後,更要把所有的流程重測一遍。於是我們在完成 後,編寫測試程式,將所有的流程通過測試程式自動跑一遍。測試驅動開發就在這種需求下誕生了。它將測試用例的開發提到了功能 之前,這樣功能 是為滿足測試用例能通過而開發,同時,測試用例也...

測試驅動開發

ttd是test driven development的簡稱,即為測試驅動開發,是極限程式設計中倡導的開發方法,倡導先寫測試再寫功能。這裡主要以我做的乙個練習測試隨機四位數的例子來講講。先介紹一下 測試的基本模組 js describe print number function beforeeac...