跳到主要內容
← 回找觀念
第五架構:防禦控制與 Git 安全網|第 3 篇

先看到紅燈,才准寫程式:TDD 為什麼能逼 AI 誠實

讓 AI 先寫功能再補測試,它會寫出「照著錯誤邏輯算出來也會過」的假測試。順序反過來:先寫測試、先跑出失敗、再寫功能到通過。Matt Pocock 的 tdd 與 code-review 兩支 Skill 把這件事寫成了規則,包括一份 12 種程式碼壞味道的檢查清單。

2026-07-31 發布 · 2026-09-16 更新 · 作者整理:Lucas

有一件事很多人用了很久 AI 才發現:叫它「寫完功能之後補上測試」,它補的測試常常是假的。

不是它故意。假設它把「滿千折百」寫錯成折兩百,你叫它補測試,它會看著自己的程式碼寫:「金額 1000 時,預期結果 800」。測試綠燈,順利通過,因為預期值是照它自己的錯誤邏輯算出來的。你以為有測試保護,其實是它自己出題自己答。

Matt Pocock 的 tdd Skill 把這種測試叫 tautological(套套邏輯):斷言用跟程式碼一樣的方式重算預期值,所以構造上一定通過,永遠不可能跟程式碼意見不同。他的規則是:預期值必須來自獨立的真相來源,已知正確的常數、一個手算的例子、規格書上的數字。

避免它的方法有一百年歷史,叫 TDD(測試驅動開發)。核心只有一個順序:

TDD 防作弊循環

Step 1Red

先證明測試會失敗。

Step 2Green

再讓 AI 寫到測試通過。

Step 3Review

檢查壞味道與作弊行為。

Step 4Refactor

在測試保護下整理。

紅燈是證據,它證明測試真的在監督

為什麼一定要先看到失敗?因為紅燈是唯一能證明「這個測試有在檢查東西」的證據。一個從來沒紅過的測試,你不知道它是真的在驗證,還是根本什麼都不檢查。先紅後綠這個順序,逼 AI 的預期值必須在程式存在之前就定下來,它沒有東西可以「照抄」。

Pocock 的 tdd Skill 把迴圈規則寫成三條,我照翻:紅在綠之前,先寫失敗的測試,再寫剛好夠通過的程式,不要預先做未來的功能;一次一片,一個介面、一個測試、一個最小實作;重構不在迴圈裡,那是審查階段的事。

還有兩個他特別點名的反模式。耦合實作:測試去 mock(假造)內部的協作者、測私有方法、或繞過介面直接查資料庫,特徵是你重構之後行為沒變,測試卻壞了。橫向切片:先把所有測試寫完、再把所有實作寫完,這樣寫出來的測試驗的是「想像中的行為」,對真實變動不敏感。他要求的是縱向:一個測試、一個實作、再下一個。

審查要用乾淨的眼睛,而且要有清單

程式寫完、測試通過之後,Pocock 的流程接一個 code-review。有兩個設計值得學。

用新的對話審。審查在獨立的子代理裡跑,不在寫程式的那場對話裡。理由是寫的那一方腦子裡還留著自己的推理,看自己的東西永遠覺得對,乾淨的眼睛才看得到問題。

審兩個軸,各有清單。一軸叫 Standards:程式有沒有照這個專案寫下來的規範。另一軸叫 Spec:程式有沒有做到原本 issue 或規格要求的事,缺了什麼、多做了什麼、看起來做了但做錯的。兩軸平行跑,結果並列,不合併排序。

Standards 那一軸有一份固定的基準清單:Fowler《重構》第三章的 12 種程式碼壞味道,每一種寫成「是什麼 → 怎麼修」:

壞味道是什麼怎麼修
Mysterious Name名字看不出在做什麼改名;改不出誠實的名字代表設計不清
Duplicated Code同樣的邏輯出現在多處抽出共用的,兩邊都呼叫它
Feature Envy方法一直去碰別的物件的資料把方法搬到它羨慕的那份資料旁
Data Clumps同幾個欄位總是一起出現包成一個型別,傳那個型別
Primitive Obsession用字串或數字代替一個領域概念給概念一個自己的小型別
Repeated Switches同一種 switch/if 串在多處重複改成多型或共用一張對照表
Shotgun Surgery改一件事要動很多檔案把一起變的東西收進同一個模組
Divergent Change一個檔案因為好幾個不相干的理由被改拆開,讓每個模組只因一種理由改
Speculative Generality為了規格沒要求的需求加抽象刪掉,等真的需要再說
Message Chains一長串 a.b().c().d()在第一個物件上藏一個方法
Middle Man一個類別幾乎只是轉發砍掉,直接呼叫真正的目標
Refused Bequest子類別忽略大部分繼承來的東西放棄繼承,改用組合

兩條使用規則:專案自己寫的規範永遠優先,規範明說可以的就不算壞味道;每一項都是判斷,不是硬性違規,報告會寫「可能有 Feature Envy」,不是「違規」。工具已經在管的,跳過。

動手做

任何有執行權限的代理工具,把紅綠規則貼在任務說明裡就行:

這個功能用 TDD 做,規則:
1. 先寫測試。預期值要來自我給的規格或例子,不准照程式邏輯推算。寫完把測試貼給我看。
2. 跑測試,必須失敗(紅燈)。把失敗訊息貼給我。沒有紅燈不准往下。
3. 寫剛好夠通過這個測試的程式,不多做。跑到綠燈。
4. 一次只做一個測試,做完再下一個。不准先把所有測試寫完。
5. 過程中不准修改測試的預期值。想改,先停下來告訴我為什麼。
規格:(貼上,含具體例子:輸入 X → 應得 Y)

用 Claude Code 或 Codex、想直接裝的,npx skills@latest add mattpocock/skills 之後,tdd 是模型自動觸發的技能,你說「用 TDD 做」或提到 red-green-refactor 它就會用;寫完打 /code-review <起點>(例如 /code-review main)跑雙軸審查。第一次要先 /setup-matt-pocock-skills 設定 issue tracker。

網頁版做不到跑測試,但做得到「預期值獨立」:交辦時先給它三組你自己算好的「輸入 → 輸出」,要求它的程式對這三組都對,不要讓它自己編例子。

做對了的樣子:每個測試你都看過它紅過一次;預期值旁邊寫得出來源(規格第幾條、哪個手算例子);審查是在另一個對話或子代理裡做的;審查報告用的是「可能有…」,不是「違規」。

找一個 AI 幫你寫過測試的功能,看那個測試的預期值是從哪來的。如果是「看起來像照程式算出來的」,那就是套套邏輯,換成你手算的數字,再跑一次。

先寫功能再補測試,AI 會寫出照錯誤邏輯也會過的假測試。紅燈是證據,沒紅過的測試不算數。預期值必須來自程式以外的地方:規格、手算、已知正確的數字。審查用乾淨的眼睛、拿著清單,而且每一項是判斷,不是判決。

站內延伸

來源: mattpocock/skills:tdd/SKILL.md(tautological、implementation-coupled、horizontal slicing 三個反模式與迴圈三規則);mattpocock/skills:code-review/SKILL.md(雙軸、平行子代理、12 種壞味道與使用規則)。12 種壞味道原出處是 Martin Fowler《Refactoring》第三章。

第五架構 · 第 3 篇 · 先紅再綠

功能先寫完再補測試,
它會自己出題自己答

什麼時候看這張:它補的測試全綠,你卻說不出那個預期數字是從哪來的。

先寫測試數字來自規格先看失敗沒紅不准寫才寫功能剛好過就好
  • 預期數字要來自規格或你手算,不准照程式推回來
  • 沒失敗過的測試,你不知道它到底有沒有在檢查
  • 審查換一場乾淨的對話,而且要拿著清單

第一個動作找一個它幫你寫過測試的功能,把預期數字換成你自己手算的再跑一次。過不了就是抓到假的了。

2026-09-16 查證稜線 Ridgeline
← 看更多找觀念文章
取得 AI 實戰工具與更新

之後會不定期整理:新方法、指令包(Prompt Pack)、Checklist 與模板。免費、無廣告;送出後會收到一封確認信,點了連結才算訂閱成功,之後每封信都附一鍵退訂。