核心觀點#
作者 Robert C. Martin 強調,單元測試(Unit Tests)對於軟體開發的重要性不亞於產品程式碼本身。
測試不僅僅是用來驗證功能的正確性,它更是一張安全網。
有這張網,開發者才能無後顧之憂地重構(Refactoring)與架構優化。
如果沒有測試,每次修改都可能引發未知的 Bug,導致程式碼逐漸腐敗(Code Rot)。
- 測試程式碼與產品程式碼同樣重要: 骯髒的測試程式碼比沒有測試更糟糕,
因為它會隨著系統演進而變得難以維護,最終成為開發的累贅- 測試帶來的好處: 它保存並加強了系統的可擴充性、可維護性與可再利用性
整潔測試的關鍵#
什麼樣的測試才算是「整潔」?答案只有一個:可讀性(Readability)。
整潔測試須具備闡明性(Clarity)、簡明性(Simplicity)和精要表達力(Density of Expression)。
測試程式碼應像故事簡單易懂,讓人一眼就能看穿它在測什麼。
測試的結構:Build-Operate-Check#
一個良好的單元測試通常遵循「建造-操作-檢查」的模式
(這也常被稱為 Arrange-Act-Assert, AAA 模式):
| 階段 | 名稱 | 說明 |
|---|---|---|
| 1 | Build (建造) | 建立測試資料,設定初始狀態 |
| 2 | Operate (操作) | 呼叫目標函式或 API |
| 3 | Check (檢查) | 驗證結果是否符合預期 |
範例:測試結構演示
def test_calculate_total_price():
# 1. Build (Arrange)
cart = ShoppingCart()
cart.add(Item("Apple", 10))
cart.add(Item("Banana", 20))
# 2. Operate (Act)
total = cart.get_total_price()
# 3. Check (Assert)
assert total == 30測試的 FIRST 法則#
為了確保測試的品質,作者提出了 FIRST 五大原則:
| 原則 | 名稱 | 說明 |
|---|---|---|
| F | Fast (快速) | 測試執行必須快,否則開發者不會頻繁執行 |
| I | Independent (獨立) | 測試案例間不應相互依賴,確保能精準定位失敗原因 |
| R | Repeatable (可重複性) | 測試應能在任何環境中重複執行 |
| S | Self-Validating (自我驗證) | 測試結果只有 Pass 或 Fail,無需人工比對 |
| T | Timely (即時) | 測試應在產品程式碼完成前撰寫 (TDD) |
測試的範圍控制#
僅測試一個概念#
一個測試函式中應儘量減少斷言(Assert)數量,
更精確地說,是應 「僅測試一個概念」。
避免長篇大論的測試:
如果一個測試函式中連續測試了「加入資料」、「修改資料」、「刪除資料」等多個步驟,
一旦中間失敗,你很難第一時間判斷是哪個環節出了問題。將其拆分為獨立的測試會更清晰。
結論#
撰寫測試並非浪費時間,而是對未來的投資。
- 良好的測試讓程式碼具備彈性(Flexibility)
- 擁有高覆蓋率且整潔的測試,就擁有修改程式碼的勇氣,因為知道任何錯誤都會被立即捕捉