writing-tests: A Cursor Skill for Generating Unit and Integration Tests for Existing Code

前言

补测试是日常开发里很常见、也很费脑的一件事:要先摸清项目用的是 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)。

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

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

Xiaoye