writing-tests:爲現有代碼生成單元與集成測試的 Cursor Skill

前言

補測試是日常開發裏很常見、也很費腦的一件事:要先摸清項目用的是 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,能力可概括爲:

  1. 檢測測試環境:從 package.json 中查找 jest、vitest、mocha、playwright、cypress 等;查找 vitest.config.ts、jest.config.ts、playwright.config.ts、.mocharc.* 等配置;閱讀已有測試文件以對齊項目習慣。
  2. 缺 runner 時協助搭建:示例以 Vitest + Testing Library 爲主,給出安裝命令與 package.json 中的 test / test:watch 腳本。
  3. 分析被測代碼:梳理對外 API(導出函數、類、組件、hooks)、條件與錯誤分支、需 mock 的依賴、文件 I/O、網絡、DOM 等副作用。
  4. 按約定落盤測試文件:與源文件同目錄或放在 __tests__/,命名如 format.ts → format.test.ts、Button.tsx → Button.test.tsx。
  5. 結構化用例:happy path、空值/邊界、拋錯、異步等;對外部模塊與 React 數據 hooks 使用 vi.mock;組件側用 Testing Library 做渲染與交互斷言。
  6. 執行並修正:運行 npm test,失敗時區分是期望寫錯還是實現問題再改。

官方還寫明「測什麼 / 不測什麼」:優先 public API、錯誤處理、邊界、狀態與異步;避免測私有實現細節、第三方庫內部、簡單 getter/setter、純類型代碼。用例名要描述場景,異步要 await 或使用 resolves / rejects。

安裝與啓用

  1. 從官方目錄獲取 Skill 文件(合集說明爲將 SKILL.md 複製到 Skill 目錄):
    - 源路徑:resources/writing-tests
  2. 放到 Cursor 可發現的位置之一:
    - 用戶級:.cursor/skills/ 下對應子目錄(內含 SKILL.md)
    - 或當前項目倉庫內的 .cursor/skills/
  3. 保存後由 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)。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜