敏捷開發-測試驅動開發優缺點(轉)

不覺間,採用測試驅動開發(Test Driven Development)半年有餘,自從看了Robert Martin的《敏捷軟件開發:原則、模式與實踐》, 就忍不住想實踐一下,親身體會書中描述的美妙景象。恰逢項目中一個全新功能交由我負責,開發週期也不是十分急迫,就拿這個新功能當回小白鼠,遵循書中的實 踐方法開始使用測試驅動開發。

  隨着開發的不斷深入,測試驅動開發的實踐漸入佳境,對其認識也從開始時的頂禮膜拜逐漸迴歸理性,在爲其優長歡欣鼓舞的同時,更理解了其不足或者說是不具備的能力。

  測試驅動開發意味着不再是從需求分析與概要設計/詳細設計後直接進入到實現代碼的編寫,而是轉而根據需求分析和概要設計進行測試用例的設計與測 試代碼的編寫,通過測試代碼硬性規定了實現代碼所必須滿足的功能需求、容錯能力。編寫實現代碼的唯一目的就是使所有測試用例成功運行,任何測試用例的失敗 都意味着實現代碼存在功能缺陷或者邏輯錯誤。之後就是不斷重複--修改或增加代碼再運行所有測試用例檢查結果--的迭代過程。

  看上去很簡單的一個過程,卻與傳統的開發格格不入,慣性的力量導致開始時很難從傳統過程的思維方式中擺脫出來。在做完需求分析與概要設計,開始 設計測試用例與編寫測試代碼時手足無措,只能摸着石頭過河,試着去做去寫,然後通過測試驅動開發的迭代過程去觀察,去體會,去修改,去適應,然後再重複迭 代過程。就這樣,漸漸理解了測試驅動開發這種“進化->測試->反饋->再進化->…”迭代循環的自然與強大,從測試中得到的反 饋不僅說明實現代碼的完備和健全與否,也給人不斷進步之感,似乎總是在腳踏實地的前進着。因爲在邁開每一步之前,都知道已有的工作經受了測試的檢驗,就具有相應的信心。即使發現有更好更優秀的設計實現,也可以放心大膽的徹底重構,因爲有測試用例和測試代碼作監督作守候。

  此外,測試驅動開發也改變了原先開發的視角,不再是直接編寫實現代碼,而是轉而從旁觀者和使用者的角度設計測試用例和測試代碼,總是能夠發現很多原先忽略的因素和條件。

  測試驅動開發的優勢在《敏捷軟件開發:原則、模式與實踐》已有詳述,我所感受到的有:

  1. 有助於設計簡單清晰而易用的接口。因爲總是先有測試代碼,才編寫實現代碼,意味着總是從使用者的角度設計接口,只有簡單易用的接口才方便測試時調用,所以我幾乎是“被迫”去努力設計簡單易用的接口,因爲我就是第一個使用者。

  2. 模塊切分的足夠小但是模塊間保持極低的耦合度。爲了方便測試,我總是盡力把重複的邏輯剝離出來,單獨構建模塊進行測試;並且儘量減少模塊間的耦合,保持模 塊相對獨立和功能完備。如果模塊過大,或者模塊間強耦合,寫測試用例與代碼時就會困難重重,笨重複雜。因爲總是先寫測試代碼,眼前的利益高於一切,將來的 實現代碼必然要遷就目前測試的需要。於是,我又“不知不覺”設計出小粒度模塊,且模塊間耦合度低的實現。

  3. 肆無忌憚的重構。因爲有測試用例和測試代碼作擔保,我終於能夠從小心翼翼心驚膽戰的重構中解脫出來,只要是更好的實現和設計,我都願意嘗試,管它呢,反正 多跑幾遍測試就知道重構的結果如何了。可以說,測試驅動開發鼓勵代碼的不斷進化,即使測試已經全部通過,也可以通過大膽重構來改進設計與實現。儘管此時是 否還需要再重構見仁見智,至少提供了一個可能,我是很喜歡這一點。

  4. 測試代碼是“活”的軟件文檔,它硬性規定了實現代碼必須滿足的需求,達不到就報錯。傳統的文本文檔比之就蒼白無力多了,“應該”,“必須”,這些字眼對程 序員有多少約束力?而且測試代碼總是能與實現代碼保持新鮮同步,傳統文檔寫完後經常被上傳服務器束之高閣,很少人問津,隨着開發組內人員的變動,往往最後 就湮沒在服務器的故紙堆之中了。

  測試驅動開發畢竟不是軟件銀彈,也不存在這樣的銀彈,它也有力不能及的地方:

  1. 測試驅動開發不可能讓人立即具有設計出優美解決方案的能力,或者說是優秀的分析與解決問題的能力。TDD不是Test Driven Design。它只是一個過程,也許可以幫助你發現並幫助你實現優美的解決方案,但是它不能變魔術一樣,只要學會了就變出一個優美的設計出來,優秀的分析 問題與解決問題的能力還是要靠不斷地學習與借鑑他人成就才能得到提高。

  2. 測試驅動開發不能節省開發投入,也很少能夠節省開發週期。測試開發所編寫的大量測試代碼都是要投入時間與精力的,我現在的代碼統計顯示,測試代碼與實現代 碼的比例基本在3:2,即使因爲測試驅動開發能得到一個簡潔的設計,也不能彌補測試代碼的工作量。當然,測試代碼可以一定程度保證高質量的實現代碼,從而 減少後期軟件測試與修正缺陷的工作週期,並進一步在軟件發佈後減少代碼修正維護的工作量。但至少在開發階段,兩相抵消,開發週期並不能有明顯改善,如果是 第一次採納測試驅動開發,甚至會延長開發週期。

  3. 測試驅動開發不能杜絕所有的軟件缺陷。儘管測試驅動開發通過測試約束,減少了程序員犯錯和遺忘的可能,但是這只是把問題從實現代碼部分地轉移到了測試代 碼。測試用例的完備與否,測試代碼本身邏輯的正確與否都依賴於程序員,糟糕的測試用例設計和測試代碼實現可能自顧不暇,也就失去了監督實現代碼的能力。我 就見過有程序員在測試代碼中讀取實現代碼生成的數據,再直接拿之來驗證實現代碼生成的數據,x必然恆等於x,這樣的測試邏輯必然成功,但是毫無意義。

  對測試驅動開發認識的深入,讓我更能合理運用它,揚其長避其短,充分享受其帶來的便利。

  測試驅動開發帶給我前所未有的軟件開發體驗,人們都說TDD是傳染病,一旦接觸就無法自拔。我想說,是的,但我心甘情願被傳染,無怨無悔,無憂無慮。借用一句英文:There’s nothing to fear, TDD is with us, amen.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章