前言¶
補測試是日常開發裏很常見、也很費腦的一件事:要先摸清項目用的是 Jest、Vitest 還是別的 runner,再對照源碼找分支和邊界,最後還要 mock 外部依賴。每次從零口述這些要求,Agent 容易漏掉約定或寫出和倉庫風格不一致的用例。把「檢測框架 → 分析代碼 → 寫 mock 與斷言 → 跑通」固化成 Skill,可以讓補測和提覆蓋率走同一條可復現流程。
這是什麼¶
writing-tests 是 awesome-cursor-skills 倉庫裏的一條 Cursor Agent Skill,維護方爲該開源合集(作者 Spencer Pauly 等貢獻者)。Skill 本體是符合 Cursor 規範的 SKILL.md 指令文件:讓 Agent 分析已有代碼,並編寫帶 mock、邊界用例與斷言的單元測試和集成測試;自動識別項目裏的測試框架,標出未覆蓋路徑,並在用戶要求加測試、提覆蓋率或針對某個模塊寫測時使用。
Cursor 會在 .cursor/skills/(個人)或項目目錄中發現 Skill 並加載;本 Skill 與合集裏其他條目一樣,屬於可複製使用的現成工作流說明,而非獨立 npm 包。
核心功能¶
依據官方 SKILL.md,能力可概括爲:
- 檢測測試環境:從
package.json中查找 jest、vitest、mocha、playwright、cypress 等;查找vitest.config.ts、jest.config.ts、playwright.config.ts、.mocharc.*等配置;閱讀已有測試文件以對齊項目習慣。 - 缺 runner 時協助搭建:示例以 Vitest + Testing Library 爲主,給出安裝命令與
package.json中的test/test:watch腳本。 - 分析被測代碼:梳理對外 API(導出函數、類、組件、hooks)、條件與錯誤分支、需 mock 的依賴、文件 I/O、網絡、DOM 等副作用。
- 按約定落盤測試文件:與源文件同目錄或放在
__tests__/,命名如format.ts→format.test.ts、Button.tsx→Button.test.tsx。 - 結構化用例:happy path、空值/邊界、拋錯、異步等;對外部模塊與 React 數據 hooks 使用
vi.mock;組件側用 Testing Library 做渲染與交互斷言。 - 執行並修正:運行
npm test,失敗時區分是期望寫錯還是實現問題再改。
官方還寫明「測什麼 / 不測什麼」:優先 public API、錯誤處理、邊界、狀態與異步;避免測私有實現細節、第三方庫內部、簡單 getter/setter、純類型代碼。用例名要描述場景,異步要 await 或使用 resolves / rejects。
安裝與啓用¶
- 從官方目錄獲取 Skill 文件(合集說明爲將
SKILL.md複製到 Skill 目錄):
- 源路徑:resources/writing-tests - 放到 Cursor 可發現的位置之一:
- 用戶級:.cursor/skills/下對應子目錄(內含SKILL.md)
- 或當前項目倉庫內的.cursor/skills/ - 保存後由 Cursor Agent 自動發現;在對話中說明「給某文件加測試」「提高覆蓋率」「爲某模塊寫測試」等意圖即可觸發(與 Skill 的
description一致)。
資料中未單獨列出 Codex CLI 或 Claude Code 的安裝差異,本文不展開。
典型用法¶
下面步驟摘自官方工作流,便於對照 Agent 實際會做什麼。
1. 確認是否已有測試棧
# Check package.json for test runner
cat package.json | grep -E "jest|vitest|mocha|playwright|cypress"
並檢查配置文件與現有 *.test.* 風格。
2. 若無 runner,示例安裝 Vitest(React 場景)
npm install -D vitest @testing-library/react @testing-library/jest-dom
在 package.json 增加:
{ "test": "vitest run", "test:watch": "vitest" }
3. 生成測試時的結構示例(Vitest)
import { describe, it, expect, vi } from "vitest";
describe("functionName", () => {
// Happy path
it("returns formatted output for valid input", () => { ... });
// Edge cases
it("handles empty string", () => { ... });
it("handles null/undefined input", () => { ... });
// Error cases
it("throws on invalid argument", () => { ... });
// Boundary conditions
it("handles maximum length input", () => { ... });
});
4. Mock 外部依賴
vi.mock("@/lib/db", () => ({
query: vi.fn().mockResolvedValue([{ id: 1, name: "test" }]),
}));
React 中可 mock 數據 hook:
vi.mock("@/hooks/useUser", () => ({
useUser: () => ({ user: { name: "Test" }, isLoading: false }),
}));
5. 組件測試(Testing Library)
import { render, screen, fireEvent } from "@testing-library/react";
it("renders the button and handles click", () => {
const onClick = vi.fn();
render(<Button onClick={onClick}>Click me</Button>);
fireEvent.click(screen.getByRole("button", { name: "Click me" }));
expect(onClick).toHaveBeenCalledOnce();
});
6. 運行
npm test
若項目原本使用 test() 而非 it(),Skill 要求 Agent 跟隨現有風格,而不是強行統一寫法。
適用場景與注意¶
適合:已有業務代碼需要補單元/集成測試;希望覆蓋率提升且用例覆蓋空值、邊界與錯誤路徑;依賴數據庫、API 或 hooks 需要穩定 mock 的模塊;React 組件需要行爲級斷言而非快照堆砌。
注意:
- Skill 示例偏 Node/React + Vitest,但第一步會檢測 Jest、Mocha、Playwright、Cypress 等;非 JS 技術棧是否適用取決於 Agent 是否能在同倉庫裏找到對等的測試約定,官方正文以 JavaScript/TypeScript 生態爲主。
- 「集成測試」在說明中與單元測試並列出現,具體邊界仍應服從項目既有分層(例如是否走真實 HTTP),Skill 強調單元側不要真實打 API 或數據庫。
- 同一合集裏另有
adding-e2e-tests、parallel-test-fixing、grinding-until-pass等條目,端到端或批量修紅測可組合使用;本文僅描述 writing-tests 本身。
結尾¶
測試生成是 AI 輔助編程裏高頻場景之一;把檢測框架、分析路徑、mock 與斷言寫成 Skill,能減少每次補測時重複交代規範的成本。官方 Skill 與說明見:writing-tests(awesome-cursor-skills)。