| name | tdd |
| description | TDD(Test-Driven Development)最佳實踐指南。當需要撰寫測試、實踐 TDD、設計測試結構、或討論測試策略時使用。也應在用戶要建置新專案、開發新功能、或寫程式練習時主動套用,確保開發流程從一開始就遵循 Red-Green-Refactor 循環,而非事後補測試。 |
TDD Best Practices Guide (2025-2026)
Canon TDD(Kent Beck 2025)
Kent Beck 在 2025 正式定義 Canon TDD:
- 寫測試清單 — 列出要覆蓋的場景(先想再寫)
- 將一個項目轉為具體、可執行的測試 — 只寫一個
- 讓測試通過(以及所有先前的測試),發現新場景就加到清單
- (可選)重構 — 不改變行為
Red-Green-Refactor
Red(紅燈)
- 寫一個單一失敗測試
- 思考 API 設計:程式碼如何被使用
- 測試必須失敗才有意義
Green(綠燈)
- 寫最少量程式碼讓測試通過
- 允許寫醜的程式碼 — 不要最佳化
- 只管讓它綠
Refactor(重構)
- 改善結構、命名、去重複、可讀性
- 不改變行為 — 測試必須全程保持綠色
- 如果重構破壞測試 → 測試耦合了實作(修測試)
Transformation Priority Premise(TPP)
Green 步驟的簡單到複雜排序,優先用上面的:
{} → nil
nil → constant
constant → constant+
constant → scalar(變數/參數)
statement → statements
unconditional → if
scalar → array
array → container
statement → recursion
if → while
expression → function
如果需要跳到複雜轉換 → 你選錯了下一個測試,重新排序測試清單。
Inside-Out vs Outside-In
Chicago School(Inside-Out)
- 從領域層向外寫到 API/Controller
- 狀態驗證(assert 物件狀態)
- 最少 mock,用真實協作者
- 適合:領域邏輯、演算法、資料轉換
- 測試更耐重構
London School(Outside-In)
- 從外層(API/Controller)向內寫
- 行為驗證(verify 協作者呼叫)
- 在過程中發現介面與依賴
- 適合:使用者功能、API endpoints、協調層
2025 共識
兩者是互補工具,不是競爭哲學:
- Chicago 用於核心領域邏輯
- London 用於整合/協調層
- 大多數有效團隊會依情境混合使用
測試結構
AAA(Arrange-Act-Assert)
it('calculates total with tax', () => {
const cart = new Cart([{ price: 100 }, { price: 200 }]);
const total = cart.totalWithTax(0.1);
expect(total).toBe(330);
});
Given-When-Then(BDD 風格)
語意相同,使用領域語言:
it('given items in cart, when calculating with 10% tax, then returns sum plus tax', () => {
const cart = new Cart([{ price: 100 }, { price: 200 }]);
const total = cart.totalWithTax(0.1);
expect(total).toBe(330);
});
原則:每個測試一個動作、一個邏輯斷言(多個 expect 可以,只要驗證同一概念)。
TDD + AI Agent(2025-2026 新趨勢)
Kent Beck 和 Simon Willison 都認為 TDD 是與 AI agent 協作的超能力:
- 人類寫測試(指定意圖)→ Agent 寫實作
- 測試防止 agent 寫出不工作或不必要的程式碼
- 自動建立回歸安全網
- 流程:寫失敗測試 → 讓 agent 產生實作 → 驗證通過 → 重構
何時 TDD 最有價值
最有價值
- 領域邏輯與商業規則
- API 開發(清楚的 input/output)
- Library / Framework 程式碼
- 演算法程式碼
- 與 AI agent 協作
- 重構既有程式碼
較不適合
- 高度實驗性/探索性程式碼(先 spike 再 TDD)
- 純 UI layout/styling
- 薄的第三方包裝
- 一次性腳本
Refactor 步驟的技巧
- 去除重複 → 合併為函式
- 改善命名 → 意圖揭示的名稱
- Extract method → 拆分大函式
- 簡化條件 → guard clause 或多態
- 引入 parameter object → 參數太多時
- 替換 magic value → 命名常數
時機:發現 code smell 立即處理,最遲不超過 3 個 baby-step。
TDD Anti-Patterns
| Anti-Pattern | 說明 |
|---|
| The Liar | 測試通過但沒測到該測的 |
| Excessive Setup | 巨大的 Arrange 代表太多依賴(設計問題) |
| The Giant | 一個測試太多斷言 |
| The Slow Poke | 測試太慢導致開發者不跑 |
| Testing Implementation | 耦合內部結構而非可觀察行為 |
| No Refactoring | 跳過 refactor 步驟 |
| 100% Coverage Obsession | 追求 100% 而非有意義的 70-80% |
| No Test List | 沒有先規劃場景就直接寫 |
Frontend vs Backend TDD
Backend
- 直觀:清楚的 input/output
- Domain service、use case、repository 都適合 TDD
- Chicago 適合領域邏輯、London 適合 controller
Frontend
- TDD 適合:元件邏輯、狀態管理、hooks、API 互動、表單驗證
- 不適合 TDD:pixel layout、CSS styling、動畫
- 測試使用者能看到和做的事(文字、互動、導航),不測 DOM 結構或 CSS class
與此專案的搭配
在 GitStar 專案中:
- Country Config / Data Collection:Chicago school — 純邏輯,用真實物件或 Fake
- 3D Visualization:Mock WebGLRenderer,測試場景邏輯
- Social Sharing:測試 OG meta 產生、URL 組裝
- 每個 task 開始前先寫測試清單,再 Red-Green-Refactor