指令用途
/tdd 是測試驅動開發 skill。它鼓勵 red → green 迴圈(refactor 階段已移至 /code-review),一次以垂直切片 / tracer bullet 的方式建構功能或修復 bug。
核心迴圈由模型早已熟悉的 leading words 來錨定,所以這個 skill 是參考導向的 —— 它不一步一步重述迴圈,而是把最耐久的觀念(垂直切片、seam —— 測試只放在預先同意的接縫處)收進反模式與簡短的「迴圈規則」清單裡。
seam 是這個 skill 對「測試要寫在哪裡」的 leading word:只在預先同意的 seams 測試,寫任何測試前都先與使用者確認 seam 在哪。
運作流程(red → green)
- Red:先寫一個會失敗的測試。它描述你接下來要加的行為,一個切片的最小一步。
- Green:寫剛好足夠的程式碼讓測試通過 —— 不多不少。
- (Refactor 不在這裡:refactor 屬於
/code-review階段。)
每個迴圈都是一個垂直切片 —— 一條從 UI/API 端點一路打到資料層、可獨立運作並通過測試的細長功能。
迴圈規則
- 一次一個切片:每個 red → green 處理一個垂直切片,而非橫向鋪一整層。
- 只在 seams 測試:寫測試前,先與使用者確認 seam 在哪;不在非 seam 處加測試。
- Red 必須真的 red:先看到測試失敗(而且失敗的原因是對的),才寫實作。
- Green 只為了讓它過:不趁機重構、不超前寫下一個切片。
- 預期值來自獨立的真實來源:不把「用同樣方式算一遍」當成 assertion(見下方反模式)。
實戰對話範例
範例一:新增折扣計算
-
You:
我想加一個「滿千打九折」的折扣功能。
-
AI:
先確認 seam。這個折扣邏輯的測試應該打哪一層?
我的建議:純邏輯函式
applyDiscount(cartTotal), seam 是這個函式的輸入輸出,不碰 DB 也不碰 UI。同意嗎? -
You:
同意。
-
AI:
Red:
test('滿千打九折', () => { expect(applyDiscount(1000)).toBe(900); });預期值
900來自獨立計算(1000 × 0.9),不是重跑程式碼。跑一下確認它 因为對的原因 失敗。 -
You:
失敗了,因為函式還不存在。
-
AI:
Green:寫剛好讓它過的實作:
export function applyDiscount(total: number): number { return total >= 1000 ? total * 0.9 : total; }跑測試,通了就進下一個切片(例如「不滿千原價」)。
反模式(重點)
同義反覆測試(tautological test)
測試的 assertion 用與實作相同的方式重新算一遍。這種測試因構造而通過,給零信心 —— 它與「實作耦合」反模式不同,是另一種毛病。
-
錯(BAD):
test('折扣(同義反覆)', () => { const inputs = [1000]; const expected = inputs.map(applyDiscount); // 用同一個函式算 expect(inputs.map(applyDiscount)).toEqual(expected); });這個測試不可能失敗,即使
applyDiscount邏輯全錯。 -
對(GOOD):預期值來自獨立的真實來源(手算、仕樣表、已知正確的參考實作):
test('折扣(獨立預期值)', () => { expect(applyDiscount(1000)).toBe(900); // 900 是手算的 ground truth });
原則:預期值必須來自獨立的真實來源,不能是把被測的程式碼重跑一遍。
橫向鋪層而非垂直切片
把整個資料層一次寫完、再寫整個 service 層、再寫 UI —— 中間沒有任何可運作的切片、沒有測試反饋。一次一個垂直切片才能讓每一圈都有 red → green 的反饋。
漂浮的 refactor
red → green 之間趁機大改結構。refactor 屬於 /code-review 階段。
何時應該使用
- 建新功能:一次一個垂直切片。
- 修 bug:先寫會失敗的測試重現 bug(與
/diagnosing-bugs的建立反饋迴圈呼應),再 green。 - 加行為:任何需要明確描述「這個行為應該是什麼」的地方。
何時不應該使用
- 探索性原型:還不確定要做什麼 —— 用
/prototype。 - 純 refactor:沒有新行為要描述 —— 屬於
/code-review。 - 一次性腳本:不值得測試覆蓋。
與其他技能的關係
/tdd 是 /implement 在預先同意的 seams 所驅動的 red-green 引擎,也是 /code-review 的上游(後者接手 refactor 階段)。它從 /codebase-design 取得介面設計指引。不確定該用哪個 skill 時,用 /ask-matt 來路由。