Community程式設計與開發github.com

toyin-software-factory/test

執行 /test 為你剛建置或修改的程式碼編寫測試套件,適用於實作功能、路由或修正之後。自動鎖定未提交的變更,讀取 test-preferences.json 以了解你的框架(若無則詢問並儲存),並根據檔案類型選擇合適的策略:快樂路徑、邊界情況、錯誤狀態、無障礙性。

test 是什麼?

這個技能旨在協助開發者在實作功能、路由或修正後,快速為未提交的變更編寫全面的測試套件。它會自動偵測 Git 工作目錄中的未提交檔案,並根據檔案類型(如邏輯、元件、API 路由、頁面/流程)選擇最合適的測試策略,包括快樂路徑、邊界情況、錯誤狀態和無障礙性。技能支援多種平台(macOS、Linux、Windows)和多種代理(如 Claude Code、Cursor),並能自動讀取或建立 test-preferences.json 以記錄使用者的測試框架偏好。其主要功能包括:透過 Git 確定測試範圍、分類檔案、安裝必要工具、撰寫測試,並可選擇在撰寫後自動執行測試套件並修復錯誤。此外,技能會遵循專案的建置方法與合約(如規格文件),確保測試只鎖定真正需要穩固的行為,避免測試暫時的鷹架。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/toyin-software-factory/factory-template/tree/HEAD/.claude/skills/test

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

輸出風格(平實用語,無破折號,無連字號)

此技能產出的所有內容(檔案與訊息)均使用平實簡單的語言。以「你」稱呼讀者,溫暖直接如同同事,每一步皆以建議呈現(可執行或跳過),而非命令。保留具有實際意義的技術術語,並以平實用語解釋每個術語。絕不使用破折號或連字號作為標點符號:無 em dash、無 en dash、也無連字複合詞。寫 read only,而非 read-only。用簡單詞語表達,或重新組織句子。程式碼、檔案路徑、命令標誌及其他技能比對用的值則保留其連字號。使用短句、逗號或括號。清晰勝過花俏。

此技能的功能

角色:擔任資深測試工程師,為程式碼撰寫應得的測試套件。測試呼叫者所依賴的、以及實際上會破壞某人的部分,而非為了覆蓋率數字而測試每一行。根據檔案內容為每個檔案選擇策略。拒絕測試那些鎖定在該切片從未打算實現的鷹架上的測試。

目標:此分支中已變更但尚未提交的程式碼。每個變更的檔案都會被分類(純邏輯、元件、API 路由、頁面/流程),並以正確的策略進行測試。主執行緒自行撰寫測試(對於大型檔案集,一個唯讀的 scout 可執行繁重的檔案讀取);若存在主導規格,則測試會追溯至其驗收標準(步驟 7 和 8)。

不撰寫應用程式程式碼。不更新 AGENTS.md/CLAUDE.md 上下文檔案(/sync 負責此工作)。

詢問 vs 直接執行

  • 當 test-preferences.json 存在、工具已安裝且存在未提交的原始碼檔案時,直接執行,無需詢問:直接開始撰寫。
  • 每次執行時總是會問一件事,即使已有偏好設定:執行測試套件後是否執行,或是提供手動操作說明(步驟 7.5)。每次執行皆可選擇,不會儲存。
  • 否則僅在以下情況詢問:無 test-preferences.json(框架;僅當頁面/流程有變更時才詢問 E2E 附加元件);所選工具未安裝(先確認);無未提交的變更(步驟 3);檔案超過 15 個(步驟 1b)。
  • 無範圍問題。Git 工作目錄樹定義了範圍。

成品所有權

  • 測試檔案(*.test.ts、*.spec.ts、test_*.py、*_test.go 等),由此技能建立
  • 專案根目錄下的 test-preferences.json,由此技能建立和維護

可攜性(任何作業系統,任何代理)

任何在 macOS、Linux 或 Windows 上的代理技能客戶端:

  • git 是唯一必需的 CLI,在所有平台上表現一致;請按所示執行 git 命令。其他 Shell 程式碼片段是 POSIX 參考,而非字面上的腳本:不要假設 find、grep、sed、cat、test/[ ]、xargs、mkdir -p 或 node -e 存在。請使用您代理的跨平台檔案工具(讀取、搜尋/glob、寫入)並自行應用分支邏輯,而非透過 Shell if/變數/重導向。
  • 捆綁檔案:相對於此技能的資料夾進行引用。主執行緒將資料夾解析為絕對路徑,並在寫入時(步驟 8)自行讀取捆綁檔案:agent-prompt.md 和 writing-guide.md。
  • 不支援互動式提問?將任何選擇題以純文字形式呈現,附帶相同選項。

在以下的 Ask 區塊中,每個選項為 "label": "description";透過您代理的選取器(在 Claude Code 上為 AskUserQuestion)或以純文字形式呈現。

執行

前置檢查(主執行緒)

1. 從 git 確定範圍(先執行此步驟,若為空,則無需詢問任何問題)

已變更但尚未提交的檔案(跨平台 git):

  • 已追蹤(暫存 + 未暫存),排除刪除:git diff --name-only --diff-filter=ACMR HEAD
  • 未追蹤且未被忽略:git ls-files --others --exclude-standard
  • 尚無提交(git diff HEAD 報錯):使用 git diff --name-only --diff-filter=ACMR --cached。

合併,移除重複項,過濾掉無法測試的檔案:

  • 測試檔案:*.test.*、*.spec.*、test_*.py、*_test.go、__tests__/、e2e/、tests/、cypress/ 下的任何內容
  • 配置:*.config.*、.*rc、tsconfig*、*.json(除非邏輯存在於 JSON 中)、Dockerfile、CI yaml
  • 鎖定檔案、.lock、產生的/建置輸出(dist/、build/、.next/、coverage/)
  • 樣式:*.css、*.scss、*.module.css;僅類型宣告:*.d.ts
  • 文件和 Markdown、規格、design.md、test-preferences.json

其餘部分即為範圍。若為空:前往步驟 3。否則繼續。

1b. 分類每個範圍內的檔案

僅根據路徑和檔案名稱進行分類,成本低廉;若確實有歧義,則標記為 logic 並在寫入時再次標記。記錄每個檔案的類別以供寫入步驟使用。

路徑/檔案名稱中的信號類別測試策略
*.tsx/*.jsx/*.vue/*.svelte,不在路由/頁面路徑下component元件測試(渲染 + 互動 + 斷言 DOM/ARIA)
app/**/page.*、pages/**(非 pages/api)、*Screen.*、*View.*page/flowE2E 候選 + 元件的元件測試
app/**/route.*、pages/api/**、*.controller.*、*.handler.*、*.resolver.*、actions.*api/server整合測試(呼叫處理器,在邊界處模擬)
純 .ts/.js/.py/.go/.rs、utils、hooks、services、領域邏輯logic單元測試(輸入 → 輸出、邊界情況、錯誤)
cli.*、bin/**、*.command.*、cmd/**cli呼叫命令的整合測試

若任何檔案為 page/flow,則 E2E_RELEVANT = yes;否則為 no。

大量差異防護:超過 15 個原始碼檔案時,不要嘗試一次全部寫入。按類別優先排序(logic 和 api/server 優先,風險最高,最容易測試完善)並詢問:

Ask: "<N> 個變更檔案數量較多,無法一次處理。我該如何聚焦?"  (header: "範圍大小")
- "Logic & API 優先(建議)": "立即測試 <count> 個 logic/api 檔案;其餘標記為尚未涵蓋"
- "批次測試所有內容": "分多次處理全部 <N> 個檔案,較慢但完整"
- "讓我縮小範圍": "我會告訴您哪些檔案或目錄最重要"

Monorepo 解析:為每個範圍內的檔案找到最近的 package.json(向上搜尋)。不同的根目錄:按根目錄分組(擁有自己的框架、套件管理器、測試目錄;按組安裝和撰寫)。一個共享的根目錄(常見情況):單一專案。記錄每個檔案的 packageRoot 以供寫入步驟使用。


2. 載入偏好設定

讀取專案根目錄下的 test-preferences.json(檔案工具;"未找到" = 無偏好設定)。根據其是否命名了 tool 進行分支,而非根據檔案是否存在:

  • tool 已設定(常見的寫入路徑):載入 tool、additionalTools、e2eTool、testDir、filePattern、packageManager;跳到步驟 5。
  • tool 為 null 且 gate 已設定(GATE_ONLY):此專案僅透過閘門進行檢查,無測試執行器,這是先前有意的選擇。不撰寫測試套件,不安裝執行器,不再次詢問,也不讀取 modes/setup.md。執行專案的型別檢查/語法檢查閘門,然後停止並報告:「此專案以 <gate> 作為閘門,而非測試套件。已執行型別檢查閘門;使用 /check verify 確認行為。」
  • 無檔案(NO_PREFS,首次執行):讀取 modes/setup.md 並執行其步驟 4(堆疊偵測和框架問題),然後返回此處進行步驟 5(安裝檢查),接著執行其步驟 6(儲存偏好設定),然後繼續到步驟 7。在寫入執行時不要讀取 modes/setup.md。
  • 格式錯誤(既未設定 tool 也未設定 gate 的檔案,或無法解析的 JSON):告知使用者,然後將其視為 NO_PREFS 並重新執行設定,這會覆蓋該檔案。

3. 無未提交的變更

範圍為空:跳過框架問題,告知工程師,提供備用方案:

Ask: "未找到未提交的原始碼變更。我該測試什麼?"  (header: "無變更")
- "上次提交": "比較 HEAD~1..HEAD 並測試該提交變更的內容"
- "特定檔案": "我將測試您指定的檔案或目錄"
- "現在不測試": "停止。我將在進行變更後執行 /test"
  • 上次提交:範圍 = git diff --name-only --diff-filter=ACMR HEAD~1 HEAD,再次執行步驟 1b。
  • 特定檔案:分類指定的檔案,繼續。
  • 不測試:正常停止。

5. 安裝檢查

使用檔案工具檢查所選的單元工具、E2E 工具(若有)和附加元件(若有):

  • JS/TS:在 node_modules/<pkg> 下,或在 package.json 的 devDependencies 中?
  • Python:在 pyproject.toml/requirements.txt 中(或使用 pip show <tool>,若 Python 可用)?
  • Go:stretchr/testify 在 go.sum 中?

全部存在 → 步驟 6。有任何缺失 → 先確認:

Ask: "<缺少的工具> 尚未安裝。立即安裝?"  (header: "安裝")
- "是,安裝並繼續": "使用偵測到的套件管理器執行安裝,然後撰寫測試"
- "否,僅撰寫可執行的骨架": "跳過安裝;撰寫測試,以便我自行安裝工具後執行"

是:使用偵測到的套件管理器進行安裝,此處以 <pkgmgr> 表示(偵測到的 npm / yarn / pnpm / bun;對於 Python/Go 使用該語言的套件管理器):

<pkgmgr> add -D vitest                                            # 單元
<pkgmgr> add -D @testing-library/<framework> @testing-library/user-event @testing-library/jest-dom  # 附加元件
<pkgmgr> add -D @playwright/test && <pkgmgr> exec playwright install  # E2E (Playwright)
<pkgmgr> add -D cypress                                          # E2E (Cypress)
pip install pytest pytest-mock                                    # Python
go get <testify module path>                                      # Go

"否":記錄 INSTALL=deferred;無論如何都會撰寫完整的測試,執行命令會報告為「安裝後執行」。


7. 收集輕量級指標(此處不要讀取大型檔案)

僅路徑和低成本信號;大型檔案的讀取將在寫入時進行(由您,或由 scout(若卸載))。此處不要讀取規格、design.md 或原始碼檔案。

使用檔案工具:

  • 列出 docs/specs/ 下最近修改的 3 個規格路徑(僅路徑)。
  • 識別主導規格:這些檔案實作的功能目錄 docs/specs/NNNN-<feature>/(或單一 docs/specs/NNNN-<feature>.md),透過分支/功能名稱或觸及的表面進行匹配(若存在 docs/scope/ 條目,則指向該規格)。記下其路徑,以及 verify.md 是否位於其旁(docs/specs/NNNN-<feature>/verify.md)。此合約是測試追溯的依據;它可能不在最近的 3 個路徑中。當存在主導規格時設定 TRACE_TO_CONTRACT = yes,否則為 no。
  • 記下 design.md 是否存在於專案根目錄;僅當範圍內有 component 或 page/flow 檔案時使用其路徑,否則為 none。
  • 讀取 AGENTS.md(標準檔案;若不存在則讀取 CLAUDE.md)作為專案上下文(簡短且成本低廉)。同時記下建置方法為一行:團隊選擇的切片塑造方法,記錄在範圍標題(或根目錄 AGENTS.md)中,例如「精簡端到端路徑」、「最精簡可用核心迴圈」、「以 UI 優先的殼層搭配佔位符」、「每個階段的完整使用者旅程」。它不會分支邏輯;而是在寫入時(步驟 8,規則 a)校準您的判斷。
  • 讀取 package.json,記下 scripts.test。當存在 test 腳本時,RUN_COMMAND = <pkgmgr> test(對於 npm 為 <pkgmgr> run test);僅在沒有腳本時才使用原始調用(例如 <pkgmgr> exec vitest run)。

7.5 詢問是否執行測試套件(總是)

Ask: "將為 <N> 個變更檔案撰寫測試。寫入後是否執行測試套件?"  (header: "執行測試?")
- "是,執行並修正至綠燈": "執行測試套件;我將修正任何測試錯誤,並標記測試捕獲的實際錯誤"
- "跳過,僅撰寫": "撰寫測試,並提供我手動執行和驗證的說明"

設定 RUN_AFTER = yes | no 並在寫入時套用。

8. 撰寫測試套件(主執行緒)

主執行緒自行撰寫測試。不要衍生撰寫器。將此技能的資料夾解析為絕對路徑,並立即(僅在現在,寫入時)讀取 agent-prompt.md 和 writing-guide.md:agent-prompt.md 是您的操作模板,writing-guide.md 是您要遵循的策略、工具規則、迭代迴圈和報告格式。讀取受測的變更檔案是唯一昂貴的部分;對於大型或不熟悉的檔案集,僅將讀取作業卸載給一個唯讀的 scout 子代理,使用最便宜的模型(Claude Code:haiku,不繼承會話模型),該子代理返回一個緊湊的對應表,然後據此撰寫。

要套用的輸入(您收集的標籤值):

  1. 單元工具、E2E 工具、附加工具、INSTALL 狀態;testDir、filePattern、套件管理器、堆疊/框架、packageRoot;分類後的範圍(每個檔案路徑及其類別:logic / component / page flow / api server / cli);RUN_COMMAND、RUN_AFTER;專案上下文加上一行建置方法;最近的 3 個規格路徑或 none(僅在與您測試的內容相關時讀取);design.md 路徑或 none;TRACE_TO_CONTRACT、主導規格路徑和 verify.md 路徑(各為 none 若不存在)。
  2. 要套用的兩個規則:(a) 讓建置方法校準哪些行為對這個切片來說是持久真實的(鎖定這些作為穩定的斷言),相對於有意的鷹架(該切片設計上偽造的)(不要斷言計畫尚未建置的真實實作,例如對一個模擬資料的殼層期望真實的後端行為)。(b) 當 TRACE_TO_CONTRACT = yes 時,讀取驗收標準(來自 verify.md(若存在,優先使用其已解析的 AC-N 標記檢查清單),否則來自規格的 ## Requirements)並鎖定持久的那些:為每一個可以固定為穩定斷言的標準提供一個自動化測試,每個測試標記上其涵蓋的 AC-N(例如 covers: AC-3 註解,或測試標題中的 AC-3),以便測試套件追溯回合約。切勿偽造無法自動化的標準(視覺/手動/環境,例如「電子郵件實際送達」);將其記錄在 NOT_COVERED 中,格式為 AC-N, <無法自動化的原因> → 延遲至 /check verify 手動步驟。

Monorepo(來自步驟 1b 的多個套件根目錄):輪流撰寫每個根目錄的測試套件,範圍限定在其根目錄的檔案、工具和套件管理器(如果大型,則將每個根目錄的檔案讀取卸載給自己的 scout)。單一根目錄(常見情況)。

…[為翻譯而截斷]

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

相關技能