測試驅動開發

測試驅動開發(TDD)是測試優先編程的一個特例,它增加了持續設計的元素。

測試驅動程式設計是指為生產程式碼編寫自動化單元測試。 之前 你編寫生產程式碼。你不會事後才寫測試(或更常見的情況是根本不寫測試),而是總是從單元測試開始。對於生產程式碼中的每一小段功能,你會先建置並執行一個小型(理想情況下非常小)、目標明確的測試,該測試會明確並驗證程式碼的功能。這個測試一開始甚至可能無法編譯,因為它所需的類別和方法可能不存在。儘管如此,它仍然起到了一種可執行規範的作用。然後,你用最少的生產程式碼讓它編譯通過,這樣你就可以執行它並觀察它是否失敗。 (有時你預期它會失敗,但它卻通過了,這本身就是有用的信息。)最後,你寫的程式碼量恰好足以讓該測試通過。

對於許多嘗試這種方法的程式設計師來說,這種技巧起初會感覺很奇怪。這有點像攀岩者小心翼翼地向上攀爬岩壁,一邊攀爬一邊在岩壁上打錨。為什麼要這麼費勁呢?難道不會大幅降低開發速度嗎?答案是,只有當你最終會大量且反覆地依賴這些單元測試時,這種方法才有意義。那些經常實踐測試優先的人聲稱,這些單元測試帶來的回報遠遠超過了編寫它們所花費的精力。

對於測試驅動開發(TDD)的工作方式,通常會使用 xUnit 系列的自動化單元測試框架(例如 Java 的 JUnit、C# 的 NUnit 等)。這些框架使得創建、運行、組織和管理大型單元測試套件變得非常簡單。 (至少在 Java 領域,它們與主流 IDE 的整合度越來越高。)這非常有用,因為在採用測試驅動開發的過程中,你會累積大量的單元測試。

先測試後工作的好處

一套完整的自動化單元測試就像一張網,能夠有效地偵測缺陷。它們能夠精確且確定性地揭示系統的當前行為。優秀的測試驅動開發團隊會發現,他們在系統生命週期中遇到的缺陷數量顯著減少,調試時間也大大縮短。編寫良好的單元測試還能作為優秀的文檔,始終與生產程式碼保持同步。一個意想不到的好處是:許多程式設計師反映,看到「綠色小條」表示所有測試都順利通過,會讓人上癮。一旦你習慣了這些頻繁出現的、關於程式碼健康狀況的正面回饋,就很難放棄它。最後,如果你的程式碼行為已經通過大量優秀的單元測試得到了充分的驗證,那麼後續開發工作將會更加輕鬆。 safer 給你 重構程式碼如果重構(或效能調整,或任何其他變更)引入了錯誤,您的測試會迅速發出警報。

測試驅動開發:更進一步

測試驅動開發 (TDD) 是測試優先編程的一種特殊形式,它加入了持續設計的元素。在 TDD 中,系統設計不再受限於紙本設計文件。相反,編寫測試和生產程式碼的過程會引導設計不斷改進。每隔幾分鐘,你就會進行重構以簡化和澄清程式碼。如果你能輕易地想到一個更清晰、更簡潔的方法、類別或整個物件模型,就朝著那個方向重構,而整個過程都由一套完善的單元測試來保護。 TDD 的核心理念是,只有當你真正深入程式碼編寫時,才能確定哪種設計才是最佳選擇。當你了解哪些方法有效、哪些無效時,你就能以最佳狀態應用這些經驗,並且記憶猶新。所有這些操作都受到自動化單元測試的保護。

你可能會從相當多的前期設計開始,儘管更常見的情況是從相當少的開始。 簡潔的程式碼設計在極限編程領域,一些白板上的 UML 草圖通常就足夠了。但在 TDD 中,初始設計有多完善並不重要,重要的是在開發過程中允許設計偏離初始狀態的程度。你可能不會進行徹底的架構變更,但如果這樣做是明智之舉,你可能會對物件模型進行大幅度的重構。有些公司比其他公司擁有更大的自主權來真正實現 TDD。

先測試後調試

將前期編寫測試所花費的時間與調試所花費的時間進行比較很有意義。調試通常需要瀏覽大量的程式碼。而先測試後做的工作方式則允許你專注於一小塊程式碼,這樣出錯的可能性就更小。管理者很難預測調試實際上需要多長時間。從某種意義上說,很多調試工作都是浪費的。調試需要投入時間、搭建鷹架,以及使用各種基礎設施(斷點、臨時變數監控、列印語句),而這些本質上都是一次性的。一旦你找到並修復了 bug,所有這些分析基本上都失去了。即使對你來說沒有完全丟失,對維護或擴展該代碼的其他程式設計師來說也肯定丟失了。而先測試後做的工作方式則不同,測試將永久存在,供所有人使用。如果某個 bug 再次出現,先前捕獲到它的同一個測試可以再次捕捉到它。如果某個 bug 的出現是因為沒有匹配的測試,你可以寫一個新的測試來捕捉它。因此,許多先測試後做的工作方式的實踐者認為,它是更聰明地工作而不是更努力工作的最佳體現。

先測試技術和工具

為系統行為的每個方面編寫單元測試並非易事。圖形使用者介面(GUI)呢?企業級介面(EJB)以及其他由容器框架管理的元件呢?資料庫和持久化機制又該如何測試?如何測試異常是否被正確拋出?如何測試性能等級?如何衡量測試覆蓋率、測試粒度和測試品質?測試優先社區正利用不斷發展的工具和技術來解答這些問題。大量的創新不斷湧現,使得使用單元測試覆蓋系統行為的每個方面成為可能。例如,使用模擬物件(fakes 或 mock 物件)將系統元件與其協作物件和外部資源隔離,進行測試驅動開發通常很有意義。如果沒有這些模擬對象,單元測試可能無法實例化被測對象。或者,對於網路連接、資料庫或圖形使用者介面等外部資源,在測試中使用真實資源可能會大幅降低測試速度,而使用虛擬或模擬版本則可以確保所有內容在記憶體中快速運行。雖然某些功能方面可能始終需要… 手動測試然而,這說法完全成立的比例卻持續下降。