Claude Code Hooks 自動執行測試怎麼做:PostToolUse、Stop 和最小驗證流程

Claude Code Hooks 自動執行測試的實作教程:什麼時候用 PostToolUse,什麼時候用 Stop,如何按文件類型選擇最小測試命令,並避免每次小改動都觸發全量測試。

Claude Code hooks 自動執行測試,最適合解決一個常見問題:你已經在 CLAUDE.md 裡寫了「改完程式碼請執行測試」,但 Claude Code 有時會忘記,有時會跑太大的測試,有時測試失敗後只給一段泛泛解釋。

Hooks 的價值,是把「希望它記得」變成「事件發生時一定執行」。對測試來說,最常用的是 PostToolUseStop

快速結論

如果只是想在 Claude Code 編輯文件後自動跑相關檢查,優先用 PostToolUse,並把 matcher 限定在 Edit|Write

如果想在 Claude Code 準備結束一輪任務時做最後驗證,適合用 Stop。但不要一開始就在 Stop 裡跑全量測試,否則一次小改動也可能變慢、變貴、變吵。

比較穩的做法是:

  1. PostToolUse 只做輕量檢查,例如格式化、型別檢查、按文件名選擇測試。
  2. Stop 做最終提醒或執行較窄的驗證腳本。
  3. 測試失敗時只輸出關鍵摘要,不把完整日誌塞回上下文。
  4. 專案級 hooks 放在 .claude/settings.json,具體邏輯放到 .claude/hooks/ 腳本。
  5. 先在小專案試跑,再推廣到團隊倉庫。

先想清楚:自動執行什麼測試

很多人配置 hooks 的第一反應是:

1
npm test

這通常不是最佳起點。自動化測試越靠近 Claude Code 的編輯動作,就越應該短、準、可重複。

場景 建議命令
改了單個前端元件 相關單測、型別檢查、lint
改了後端函式 相關 package 的單測
改了配置文件 配置校驗、build dry run
改了 Markdown 連結檢查或 front matter 檢查
準備結束任務 彙總執行一次最小驗證
準備提交或發布 手動執行完整測試和構建

Hooks 不應取代 CI。它更像本地安全網:及時發現明顯錯誤,減少 Claude Code 在錯誤方向上連續改文件。

推薦目錄結構

不要把複雜邏輯全部塞進 settings.json 的一行命令裡。

1
2
3
4
5
6
your-repo/
  .claude/
    settings.json
    hooks/
      run-related-tests.sh
      final-check.sh

Windows 專案也可以用 PowerShell:

1
2
3
4
5
6
your-repo/
  .claude/
    settings.json
    hooks/
      run-related-tests.ps1
      final-check.ps1

真正落地時,按團隊常用 shell 選一種即可。

用 PostToolUse 在編輯後跑相關測試

PostToolUse 會在工具呼叫之後觸發。自動測試場景通常只關心寫文件工具,所以 matcher 可以限制為 Edit|Write

.claude/settings.json 示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run-related-tests.sh"
          }
        ]
      }
    ]
  }
}

這個配置只負責註冊 hook。真正判斷「改了什麼文件、該跑什麼測試」,放到腳本裡。

Bash 腳本:按文件類型選擇命令

.claude/hooks/run-related-tests.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env bash
set -euo pipefail

INPUT="$(cat)"
FILE_PATH="$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // empty')"

if [ -z "$FILE_PATH" ]; then
  exit 0
fi

case "$FILE_PATH" in
  *.ts|*.tsx)
    echo "Running TypeScript checks for $FILE_PATH"
    npm run typecheck -- --pretty false
    ;;
  *.test.ts|*.spec.ts|*.test.tsx|*.spec.tsx)
    echo "Running focused test for $FILE_PATH"
    npm test -- "$FILE_PATH" --runInBand
    ;;
  *.py)
    echo "Running Python checks for $FILE_PATH"
    python -m pytest -q
    ;;
  *.md)
    echo "Markdown changed: skip code tests"
    ;;
  *)
    echo "No related test rule for $FILE_PATH"
    ;;
esac

然後賦予執行權限:

1
chmod +x .claude/hooks/run-related-tests.sh

這個腳本刻意保守。它不直接跑全量測試,也不輸出很長日誌。

PowerShell 版本

.claude/hooks/run-related-tests.ps1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$inputJson = [Console]::In.ReadToEnd()
if ([string]::IsNullOrWhiteSpace($inputJson)) {
  exit 0
}

$payload = $inputJson | ConvertFrom-Json
$filePath = $payload.tool_input.file_path

if ([string]::IsNullOrWhiteSpace($filePath)) {
  exit 0
}

switch -Regex ($filePath) {
  '\.tsx?$' {
    Write-Output "Running TypeScript checks for $filePath"
    npm run typecheck -- --pretty false
    break
  }
  '\.(test|spec)\.tsx?$' {
    Write-Output "Running focused test for $filePath"
    npm test -- $filePath --runInBand
    break
  }
  '\.py$' {
    Write-Output "Running Python checks for $filePath"
    python -m pytest -q
    break
  }
  '\.md$' {
    Write-Output "Markdown changed: skip code tests"
    break
  }
  default {
    Write-Output "No related test rule for $filePath"
  }
}

對應的 .claude/settings.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "powershell.exe -ExecutionPolicy Bypass -File \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-related-tests.ps1\""
          }
        ]
      }
    ]
  }
}

先在普通終端手動跑腳本,再放進 hook。

測試失敗時 Claude Code 會怎樣

Hook 命令輸出會進入 Claude Code 的工作流。測試失敗時,Claude Code 通常會看到錯誤輸出,然後繼續修復。

這裡有兩個坑。

第一,失敗輸出不要太長。可以只保留最後幾十行:

1
npm test -- "$FILE_PATH" --runInBand 2>&1 | tail -n 80

第二,測試命令要穩定。不要讓 hook 依賴互動式輸入、隨機端口、臨時網路服務或人工確認。

用 Stop 做最終檢查

PostToolUse 適合「編輯後立即檢查」。Stop 適合「這一輪準備結束前再確認」。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/final-check.sh"
          }
        ]
      }
    ]
  }
}

.claude/hooks/final-check.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/usr/bin/env bash
set -euo pipefail

if git diff --quiet; then
  echo "No working tree changes. Skip final checks."
  exit 0
fi

echo "Working tree changed. Suggested final checks:"
echo "- run the focused test command for touched files"
echo "- run typecheck if code changed"
echo "- run full test suite before commit or deploy"

剛開始啟用 hooks 的團隊,可以先用提醒版,不要立刻自動跑昂貴命令。

什麼時候不要自動跑測試

以下情況要謹慎:

  • 單測很慢;
  • 測試需要資料庫、佇列、瀏覽器或外部 API;
  • 測試會改本地資料;
  • 測試日誌很大;
  • 專案還沒有穩定的最小測試命令;
  • 團隊經常讓 Claude Code 批量改很多文件。

這種情況下,hook 可以先提示應執行什麼命令,而不是自動執行。

按風險分級

風險 自動動作
低風險 格式化、lint 單文件、Markdown 檢查
中風險 型別檢查、相關單測、配置校驗
高風險 全量測試、E2E、構建、資料庫遷移檢查

低風險可以放進 PostToolUse。中風險可以按文件類型觸發。高風險最好放到人工確認、CI 或發布流程裡。

和 CLAUDE.md 怎麼分工

CLAUDE.md 適合寫原則:

1
2
3
改動完成後優先執行最小相關測試。
測試失敗時先修復失敗原因,不要繞過測試。
不要為了一次小改動執行全量 E2E,除非使用者要求。

Hooks 適合寫執行:

1
2
當 Edit 或 Write 發生後,執行 run-related-tests.sh。
當 Stop 發生時,輸出最終檢查建議。

CLAUDE.md 告訴 Claude Code 應該怎麼想;hooks 負責到點就做。

排錯清單

如果 hook 沒有執行:

  1. 在 Claude Code 輸入 /hooks,確認事件是否註冊。
  2. 確認 settings.json 是合法 JSON。
  3. 確認事件名正確,例如 PostToolUseStop
  4. 確認 matcher 能匹配工具名,例如 Edit|Write
  5. 確認腳本路徑正確。
  6. macOS/Linux 確認腳本有執行權限。
  7. Windows 確認 PowerShell 執行策略和引號沒問題。
  8. 先印一行 echo hook fired 做最小驗證。
  9. 不要一開始就接複雜測試命令。
  10. 如果輸出太長,先改成摘要。

團隊使用建議

團隊倉庫啟用 Claude Code hooks,建議從最小版本開始:

  1. 只加通知或最終檢查提醒。
  2. 自動化前端格式化、Markdown、型別檢查這類低風險命令。
  3. 再按目錄或文件類型增加相關單測。
  4. 全量測試交給 CI,不要塞進每次 Claude Code 編輯後。

參考資料

總結

Claude Code hooks 自動執行測試的關鍵,不是把 npm test 塞進配置,而是把驗證流程拆細。

編輯後用 PostToolUse 做輕量、相關、可重複的檢查;結束前用 Stop 做最終提醒或窄範圍驗證;全量測試仍然交給人工確認和 CI。把規則寫進 CLAUDE.md,把動作放進 .claude/hooks/,再用 /hooks 驗證註冊狀態。

记录并分享
使用 Hugo 建立
主題 StackJimmy 設計