--- description: 寫下一個測試(Red 階段)。一次只寫一個最小的測試,讓它失敗。 --- # TDD Red - 寫下一個測試(Red) 寫下一個小測試,看它失敗。 **【功能名】**:{{feature_name}} ## Kent Beck 的 Red 階段理念 > "寫一個小測試。讓它失敗。" ### 一次一個測試的原則 **為什麼一次只寫一個?** - 保持專注 - 快速反饋 - 小步前進 - 容易回退 ### 如何選擇下一個測試? Kent Beck 的建議: 1. **從 To-Do List 選**(心理 To-Do,不是文件) - 腦中想到什麼測試,記下來 - 選最簡單的開始 2. **從上一個測試的經驗** - 上一個測試通過了,下一步自然浮現 - "如果這樣,那會怎樣?" 3. **三角測量** - 如果不確定實作,寫第二個類似的測試 - 從多個角度逼近正確實作 ## 寫測試的步驟 ### 1. 更新 journey.md ```markdown ### 第 N 輪 - {日期時間} #### 🤔 想法 {為什麼要寫這個測試?從上一輪學到什麼?} #### 🔴 Red - 寫測試 測試名稱:{測試名稱} ``` ### 2. 寫測試程式碼 **測試結構:Given-When-Then** ```javascript test('簡短描述測試意圖', () => { // Given - 準備 // 【準備】:{為什麼需要這些資料?} const input = testData; // When - 執行 // 【執行】:{測試什麼行為?} const result = functionUnderTest(input); // Then - 驗證 // 【驗證】:{為什麼期待這個結果?} expect(result).toBe(expected); }); ``` ### 3. 執行測試,確認失敗 ```bash npm test ``` **必須看到失敗!** - 如果沒失敗,測試可能有問題 - 失敗訊息要清楚 ### 4. 記錄失敗訊息 在 journey.md 中: ```markdown #### 失敗訊息 ``` {實際的錯誤訊息} ``` #### 📝 下一步 執行 /kb-green 讓測試通過 ``` ## 測試大小的藝術 ### 測試要多小? Kent Beck 的答案:**取決於你的信心** **信心低(不確定)**: - 寫更小的測試 - 更頻繁的反饋 **信心高(很確定)**: - 可以寫大一點的測試 - 跨越明顯的步驟 ### 範例:小測試 vs 大測試 **小測試(信心低時)**: ```javascript // 第 1 個測試:最基本的 test('5 元乘以 2 等於 10 元', () => { const five = new Dollar(5); const product = five.times(2); expect(product.amount).toBe(10); }); // 第 2 個測試:檢查副作用 test('乘法不改變原物件', () => { const five = new Dollar(5); five.times(2); expect(five.amount).toBe(5); // 原值不變 }); ``` **大測試(信心高時)**: ```javascript // 直接測試完整行為 test('Dollar 乘法運算', () => { const five = new Dollar(5); const ten = five.times(2); expect(ten.amount).toBe(10); expect(five.amount).toBe(5); // 也檢查副作用 }); ``` ## 三角測量的時機 當你不確定實作時,用三角測量: ```javascript // 第 1 個測試 test('1 + 1 = 2', () => { expect(add(1, 1)).toBe(2); }); // 最簡單的假實作 function add(a, b) { return 2; // 硬編碼 } // 第 2 個測試(三角測量) test('2 + 3 = 5', () => { expect(add(2, 3)).toBe(5); }); // 現在必須寫真正的實作 function add(a, b) { return a + b; } ``` ## To-Do List 技巧 Kent Beck 建議在測試程式碼中寫註解: ```javascript describe('Dollar', () => { // TODO: 測試加法 // TODO: 測試負數 // TODO: 測試相等性 test('乘法', () => { // 目前的測試 }); }); ``` 或在 journey.md 中: ```markdown ## 心理 To-Do List - [x] 基本乘法 - [ ] 乘法副作用 - [ ] 加法運算 - [ ] 負數處理 ``` ## 常見問題 ### Q: 要不要測試所有邊界情況? Kent Beck:**不用一開始就全測** - 先從明顯的案例開始 - 邊界情況在需要時再加入 - 讓測試自然演進 ### Q: 測試名稱要多詳細? Kent Beck:**描述意圖,不是實作** ```javascript // ✅ 好的測試名稱 test('購物車加入商品後,總價增加') // ❌ 不好的測試名稱 test('testAddItem') ``` ### Q: 要寫測試到什麼程度? Kent Beck:**寫到你有信心為止** - 如果還不確定,再寫一個測試 - 如果已經確定,可以跳到實作 ## 範例:Money 第一個測試 ```javascript // __tests__/money.test.js describe('Dollar', () => { test('乘法運算', () => { // 【準備】:建立 5 元的 Dollar 物件 const five = new Dollar(5); // 【執行】:乘以 2 const product = five.times(2); // 【驗證】:結果應該是 10 元 expect(product.amount).toBe(10); }); }); ``` 執行測試: ```bash npm test # 結果:失敗! # Error: Dollar is not defined ``` 在 journey.md 記錄: ```markdown ### 第 1 輪 #### 🔴 Red - 寫測試 測試名稱:Dollar 乘法運算 #### 失敗訊息 ``` Error: Dollar is not defined ``` #### 📝 下一步 執行 /kb-green 建立 Dollar 類別 ``` ## 下一步 測試寫好且失敗了?執行: ``` /kb-green ``` 用最簡單的方式讓測試通過! ## 記住 > "測試不是目的,而是思考的工具。" > "失敗的測試是進步的開始。" > "一次一小步,但要持續前進。"