精選
TDD Testing Workflow Automation
Claude Code TDD:AI 輔助測試驅動開發完整指南
學習如何用 Claude Code 實踐 TDD。包含完整的 Red-Green-Refactor 流程、Hooks 自動化配置,以及 CLAUDE.md 設定範例。
2026年1月19日 • 10 min read • 作者:Claude World
TDD(測試驅動開發)是 Anthropic 官方推薦的 Claude Code 工作流程之一。這篇文章教你如何讓 Claude 自動遵循 Red-Green-Refactor 循環,寫出品質更高的程式碼。
為什麼選擇 TDD + Claude Code?
Claude Code 最擅長的是有明確目標的任務。測試就是最好的目標:
傳統方式:寫程式碼 → 手動測試 → 發現 bug → 修復 → 重複
TDD:寫測試 → 測試失敗(Red)→ 寫程式碼讓測試通過(Green)→ 重構
Claude + TDD 的優勢:
| 優勢 | 說明 |
|---|---|
| 明確的成功標準 | 測試通過 = 任務完成 |
| 自動迭代 | Claude 可以執行測試、查看結果、修復問題 |
| 減少來回確認 | 不需要手動確認「這樣有沒有成功?」 |
| 程式碼品質 | 自然地具備測試覆蓋率 |
TDD 基礎:Red-Green-Refactor
三個階段
┌─────────────────────────────────────────────────────────┐
│ │
│ 🔴 RED 🟢 GREEN 🔄 REFACTOR │
│ │
│ 寫一個會 寫最少量的 改善程式碼 │
│ 失敗的測試 程式碼讓測試通過 保持測試通過 │
│ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ 測試必須失敗 測試必須通過 測試仍然通過 │
│ │
└─────────────────────────────────────────────────────────┘
實際範例
步驟一:Red
你:寫一個測試,驗證 add(2, 3) 回傳 5
Claude:
// add.test.js
test('add(2, 3) should return 5', () => {
expect(add(2, 3)).toBe(5);
});
// 執行測試
npm test
// ❌ FAIL - add is not defined
步驟二:Green
你:讓測試通過
Claude:
// add.js
function add(a, b) {
return a + b;
}
// 執行測試
npm test
// ✅ PASS
步驟三:Refactor
你:重構程式碼,加上型別檢查
Claude:
// add.ts
function add(a: number, b: number): number {
return a + b;
}
// 執行測試
npm test
// ✅ PASS(測試仍然通過)
CLAUDE.md 配置
基本 TDD 規則
在專案根目錄的 CLAUDE.md 中加入:
# TDD 開發規則
## 核心原則
1. **測試優先**:任何新功能都必須先有失敗的測試
2. **最小實作**:只寫剛好能讓測試通過的程式碼
3. **持續重構**:每次亮綠燈後考慮重構
## 開發流程
1. 接到需求 → 先寫測試
2. 確認測試失敗(Red)
3. 寫最少量程式碼讓測試通過(Green)
4. 重構(保持 Green)
5. 重複
## 禁止事項
- ❌ 不要在沒有測試的情況下寫功能程式碼
- ❌ 不要刪除或跳過現有測試
- ❌ 不要寫「等等再補測試」的程式碼
Hooks 自動化配置
自動執行測試
每次修改程式碼後自動執行測試:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npm test -- --passWithNoTests --watchAll=false 2>/dev/null",
"onFailure": "warn"
}
]
}
]
}
}
強制 TDD:測試通過才能完成
{
"hooks": {
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "npm test -- --passWithNoTests",
"onFailure": "block"
}
]
}
]
}
}
完整 TDD Hook 配置
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "prompt",
"prompt": "Check if writing feature code. If yes, confirm corresponding test file exists. If test doesn't exist, remind to write tests first. Return 'approve' or reminder message."
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npm test -- --passWithNoTests --watchAll=false",
"onFailure": "warn"
}
]
}
],
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "prompt",
"prompt": "Check: 1) Was feature code added or modified? 2) If yes, do corresponding tests exist and pass? If tests don't exist or fail, return 'block' with explanation. Otherwise return 'approve'."
},
{
"type": "command",
"command": "npm test",
"onFailure": "block"
}
]
}
]
}
}
實戰範例:Todo 應用程式
讓我們用 TDD 實作一個簡單的 Todo 功能。
步驟一:定義需求
需求:實作 TodoList 類別
- addTodo(text):新增待辦事項
- getTodos():取得所有待辦事項
- completeTodo(id):標記為已完成
- getCompletedCount():取得已完成的數量
步驟二:第一個測試(Red)
你:用 TDD 實作 TodoList。先寫第一個測試:新增待辦事項。
Claude 生成:
// todoList.test.js
const { TodoList } = require('./todoList');
describe('TodoList', () => {
describe('addTodo', () => {
test('should add a todo item', () => {
// Arrange
const todoList = new TodoList();
// Act
todoList.addTodo('Buy milk');
// Assert
const todos = todoList.getTodos();
expect(todos).toHaveLength(1);
expect(todos[0].text).toBe('Buy milk');
});
});
});
執行測試:
npm test
# ❌ FAIL - Cannot find module './todoList'
步驟三:最小實作(Green)
你:讓測試通過,寫最少量的程式碼。
Claude 生成:
// todoList.js
class TodoList {
constructor() {
this.todos = [];
}
addTodo(text) {
this.todos.push({ text });
}
getTodos() {
return this.todos;
}
}
module.exports = { TodoList };
執行測試:
npm test
# ✅ PASS
步驟四:下一個測試
你:繼續 TDD,加入 completeTodo 功能的測試。
// todoList.test.js(新增)
describe('completeTodo', () => {
test('should mark a todo as completed', () => {
// Arrange
const todoList = new TodoList();
todoList.addTodo('Buy milk');
const todoId = todoList.getTodos()[0].id;
// Act
todoList.completeTodo(todoId);
// Assert
const todo = todoList.getTodos()[0];
expect(todo.completed).toBe(true);
});
});
npm test
# ❌ FAIL - todo.id is undefined
步驟五:擴充實作
你:讓測試通過。
// todoList.js(更新版)
class TodoList {
constructor() {
this.todos = [];
this.nextId = 1;
}
addTodo(text) {
this.todos.push({
id: this.nextId++,
text,
completed: false
});
}
getTodos() {
return this.todos;
}
completeTodo(id) {
const todo = this.todos.find(t => t.id === id);
if (todo) {
todo.completed = true;
}
}
}
module.exports = { TodoList };
npm test
# ✅ PASS(共 2 個測試)
TDD 常見問題
Q:哪些情況不適合 TDD?
A:
- 探索性的原型開發(還不確定要做什麼)
- UI 樣式調整
- 設定檔變更
這些情況下,可以先寫程式碼,之後再補測試。
Q:測試要寫多詳細?
A:遵循測試金字塔:
/\
/ \ E2E(少量)
/----\
/ \ 整合測試(中等)
/--------\
/ \ 單元測試(大量)
Q:Claude 跳過測試直接寫程式碼怎麼辦?
A:在提示詞中明確說明:
你:用 TDD 實作這個功能。
步驟一:先寫會失敗的測試
步驟二:等我確認測試失敗後,再寫程式碼
或者使用 Hooks 強制執行:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "prompt",
"prompt": "If writing feature code (not tests), check if test file exists. If not, return 'block' and remind to write tests first."
}
]
}
]
}
}
最佳實踐總結
1. 提示詞範本
用 TDD 實作 [功能描述]:
1. 先寫會失敗的測試
2. 確認測試失敗後,寫最少量程式碼讓測試通過
3. 所有測試通過後,考慮重構
2. 檢查清單
每個新功能:
- 先寫測試
- 確認測試失敗(Red)
- 寫程式碼讓測試通過(Green)
- 重構(保持 Green)
- 檢查覆蓋率
3. 推薦配置組合
| 工具 | 用途 |
|---|---|
| CLAUDE.md | 定義 TDD 規則 |
| Hooks | 自動執行測試 |
| Stop Hook | 強制測試通過 |
下一步
掌握 TDD 工作流程後,建議繼續閱讀:
- Hooks 完整教學 - 更多自動化配置
- 自訂 Agents - 建立專屬的測試 agent
- Director Mode - 進階開發模式
參考資源
最後更新:2026-01-19