跳到主要內容
maxstudioNews
AI 自動化DEV Community (Codex)約 8 分鐘

提升 AI 程式碼代理效率:從失敗測試開始

本文介紹一套四步驟的測試驅動開發(TDD)工作流程,專為 AI 程式碼代理設計。核心理念是讓代理先編寫失敗測試並確認其失敗,然後再進行程式碼實作,以確保產出更可靠且符合規格的程式碼。這種方法能有效避免代理在實作後才回填測試的問題。

提升 AI 程式碼代理效率:從失敗測試開始
圖片來源:DEV Community (Codex)

這篇文章最初發表於 https://aicoding-guide.com。當你要求程式碼代理「實作這個功能」時,它通常能快速完成,但驗證環節往往只停留在「它應該能運作」。最有效的解決方案是讓代理先編寫一個失敗測試,確認測試確實失敗後,再進行實作。

一個擁有明確目標(例如「讓這個測試通過」)的代理,可以自行進行迭代。本文將介紹適用於所有三種工具的提示詞,以及工具專屬的強制執行規則而非僅僅請求的方法。

重點

你將學到:

  • 工作流程的四個步驟及每個步驟的提示詞
  • 情境檔案(CLAUDE.md / AGENTS.md / GEMINI.md)中應包含的內容
  • 如何阻止代理修改測試,以及當出現問題時該怎麼辦

四個步驟

| 步驟 | 發生什麼事 | 告訴代理什麼 |

| :----------- | :----------------------------------------- | :--------------------------------------------- |

| 1. 編寫測試 | 根據規格產生一個失敗測試 | 說「還不要寫實作」 |

| 2. 確認失敗 | 執行測試並看到它失敗 | 讓它確認失敗是「尚未實作」 |

| 3. 實作 | 修改實作直到測試通過 | 說「不要修改測試」 |

| 4. 清理 | 移除重複、改進命名、增加案例 | 讓它確認之後測試仍然通過 |

重要的是,步驟 1 和步驟 3 是獨立的指令。如果將它們合併成一個指令(例如「編寫測試並實作」),代理往往會先寫實作,然後再回填一個符合實作的測試。

提示詞

步驟 1:只寫測試

我想要在 src/lib/pricing.ts 中有一個 calculateTotal 函式,它根據數量和單價回傳折扣後的總價。規格如下:

  • 數量達到 10 或更多時打 95 折,100 或更多時打 9 折
  • 如果數量為 0 或更少,則拋出錯誤
  • 分數無條件捨去

首先,只在 src/lib/pricing.test.ts 中為此規格編寫測試。還不要寫實作。測試寫好後,執行 pnpm test pricing,確認所有測試都因為函式不存在而失敗,然後回報結果。

步驟 2-3:實作

實作 calculateTotal,讓 pricing.test.ts 中的所有測試都通過。不要修改測試檔案。如果你認為某個測試有誤,請說明原因但不要修改它。之後執行 pnpm test pricing 並貼上結果。

步驟 4:清理

審查實作和測試,清理重複或不明確的命名。如果缺少任何邊界案例(9、10、99、100),請新增。最後執行 pnpm test pricing 和 pnpm lint 並回報結果。

詞彙表

邊界案例:指規格行為改變的點(10、100)以及這些點兩側(9、11)的測試。代理通常只測試「代表性」的值,因此明確要求邊界案例會很有幫助。

將其放入情境檔案

如果重複這些指令讓你感到厭倦,可以將工作流程寫入你的情境檔案。相同的文字適用於所有三種工具:

```

如何實作(測試優先)

1. 對於新功能或修復,請先編寫一個失敗測試並執行它以確認失敗

2. 實作直到測試通過。在實作期間不要修改測試檔案

3. 如果你判斷某個測試有誤,請說明原因但不要修改它,並等待指令

4. 在你的報告中包含你執行的測試指令及其結果(通過/失敗計數)

5. 如果沒有測試設定,請先提議設定一個

```

關於如何在三個檔案中保留一份文字,請參閱 CLAUDE.md、AGENTS.md 和 GEMINI.md,它們僅在載入方式上有所不同。

Claude Code:使用鉤子強制執行

在 Claude Code 中,你可以將其變成一種機制而非請求。文件明確指出情境檔案是「情境,而非強制配置」,並指出可以使用 PreToolUse 鉤子來阻止代理的動作,無論 Claude 決定什麼。以下是一個在實作階段阻止編輯測試檔案的鉤子:

```bash

#!/usr/bin/env bash

.claude/hooks/protect-tests.sh

Only blocks test-file edits when PROTECT_TESTS=1

[ "${PROTECT_TESTS:-0}" = "1" ] || exit 0

file=$(jq -r '.tool_input.file_path // empty')

case "$file" in

.test. | .spec. | /__tests__/*)

echo "Test files can't be changed during the implementation phase: $file. If a test is wrong, report why." >&2

exit 2

;;

esac

exit 0

```

```json

{

"hooks": {

"PreToolUse": [

{

"matcher": "Edit|Write|NotebookEdit",

"hooks": [

{

"type": "command",

"command": "bash .claude/hooks/protect-tests.sh"

}

]

}

]

}

}

```

PreToolUse 上的結束碼 2 會阻止工具呼叫,因此從 PROTECT_TESTS=1 開始,Claude Code 可以讓篡改測試變得物理上不可能,而不僅僅是勸阻。有關鉤子的基本知識,請參閱「使用 Claude Code 鉤子在儲存時執行 lint 和格式化」。

透過技能修復程序:將這四個步驟寫入 /tdd <spec> 斜線指令中,可以讓每次執行都保持在相同的軌道上(請參閱「建立你自己的斜線指令」)。將測試執行委託給子代理可以避免冗長的測試輸出佔用你的主要情境。

Codex 和 Gemini CLI

這兩者都沒有等效的鉤子,因此你必須依賴指令和檢查來執行此操作。Codex:在實作階段使用 --sandbox workspace-write,並在批准前使用 /diff 檢查測試檔案是否未更改。將工作流程放入 AGENTS.md 中。Gemini CLI:開啟檢查點功能,如果測試檔案被修改,則使用 /restore 回溯。將工作流程放入 GEMINI.md 中。

當出錯時

| 症狀 | 怎麼辦 |

| :--------------------------------- | :------------------------------------------------------------------------------------------------- |

| 它在測試步驟中編寫了實作 | 在提示詞的結尾也重複「還不要寫實作」。在 Claude Code 中,使用規劃模式(plan mode)只獲取規劃。 |

| 當測試無法通過時,它放鬆了測試 | 聲明「不要修改測試」,並使用鉤子阻止它。 |

| 測試都是模擬(mocks),毫無證明力 | 說「如果必須,可以模擬外部依賴,但絕不能模擬被測試函式的邏輯」。 |

| 測試執行時間過長 | 在提示詞中加入縮小範圍的指令(例如 pnpm test pricing)。 |

總結

  • 將「編寫測試」和「實作」設為獨立的指令,並在兩者之間確認失敗。
  • 每次都聲明「不要修改測試檔案」和「在你的報告中包含測試結果」,或者將它們放入你的情境檔案中。
  • Claude Code 可以使用 PreToolUse 鉤子阻止測試檔案編輯,並透過技能修復程序。
  • 對於 Codex 和 Gemini CLI,使用 /diff 或檢查點功能來檢查測試是否未被篡改。
Share

覺得值得一看?分享給朋友。

以上為 AI 自動翻譯導讀。原文版權歸 DEV Community (Codex) 所有, 建議透過「閱讀原文」前往原始網站,以取得最完整資訊並支持原作者。

Newsletter

不用每天追,AI 重點每週寄給你

43 個來源、每 2 小時更新,太多看不完。電子報每週挑最值得看的幾則,附上 Max 的看法。

每週一封。Email 只用來寄電子報,每封信都能一鍵退訂。