本 skill 面向 代码已存在、需要补充测试 的场景(区别于 TDD 先写测试再写代码)。 通过五个阶段,从项目理解到测试交付,系统性地为已有项目生成高质量测试。
核心理念:
支持两种安装方式,使用 AskQuestion 让用户选择:
项目级安装(推荐协作项目,跟随 git 提交,团队共享):
bash
mkdir -p .cursor/skills && cp -r /path/to/test-gen .cursor/skills/test-gen
# 同时安装斜杠命令
mkdir -p .cursor/commands && cp /path/to/test-gen.md .cursor/commands/test-gen.md
用户级安装(个人全局使用,跨项目可用):
bash
mkdir -p ~/.cursor/skills && cp -r /path/to/test-gen ~/.cursor/skills/test-gen
项目级安装的 skill 优先于用户级。如果两处都存在,项目级生效。 用户级安装时不支持斜杠命令(命令只能放在项目的
.cursor/commands/下)。
在开始前,自动检测项目环境:
text
检测清单:
1. 语言 — 扫描文件后缀和配置文件(package.json / go.mod / pyproject.toml / pom.xml / Cargo.toml 等)
2. 测试框架 — 检查已有依赖(jest / vitest / pytest / go test / JUnit / RSpec 等)
3. 已有测试 — 搜索 *_test.* / *.test.* / *.spec.* / test_*.* 文件
4. 覆盖率工具 — 检查是否已配置(nyc / c8 / coverage.py / go cover 等)
5. 设计文档 — 搜索 README / ARCHITECTURE / docs/ / DESIGN.md
6. 构建系统 — 检查 Makefile / Taskfile / justfile 是否存在
7. VCS 状态 — 检查 git 是否可用(用于后续变更行覆盖率)
如果检测到项目 有测试框架但没有覆盖率工具,自动安装:
语言条件安装命令Python有 pytest 但无 pytest-covpip install pytest-covJS/TS (Jest)无 --coverage 配置已内置,无需安装JS/TS (Vitest)无 @vitest/coverage-*npm install -D @vitest/coverage-v8Go—内置 go test -cover,无需安装Rust无 cargo-tarpaulin/llvm-covcargo install cargo-llvm-covJava (Maven)无 JaCoCo 插件在 pom.xml 中添加 JaCoCo 插件配置Java (Gradle)无 jacoco 插件在 build.gradle 中添加 id 'jacoco'C#/.NET无 coverletdotnet add package coverlet.collector
安装前使用 AskQuestion 确认:
text
检测到项目缺少覆盖率工具。建议安装:
- [工具名] (安装命令: `xxx`)
是否立即安装?
详细的安装配方见 coverage-recipes.md。
将检测结果汇报给用户,确认无误后进入覆盖率阈值加载。
在前置检测完成后、进入 Phase 1 之前,加载覆盖率阈值。
三层阈值,各自独立判定:
yaml
coverage_thresholds:
overall: # 全项目总体阈值
line: 80 # 行覆盖率 %
branch: 70 # 分支覆盖率 %
function: 80 # 函数覆盖率 %
per_file: # 单文件阈值(任何单文件不低于此值)
line: 60
branch: 50
delta: # 变更行覆盖率阈值
line: 90 # 新增/修改的代码行覆盖率
按顺序查找,找到即停:
项目配置文件 .test-gen.yaml(项目根目录)
yaml
coverage_thresholds:
overall:
line: 85
branch: 75
function: 85
per_file:
line: 70
branch: 60
delta:
line: 95
项目包管理配置中的嵌入字段
pyproject.toml: [tool.test-gen.coverage_thresholds]package.json: "test-gen": { "coverage_thresholds": { ... } }默认值(上方定义的 80/70/80、60/50、90)
加载后向用户展示当前生效的阈值及来源。
overall + per_file 阈值逐项对比delta 阈值对比--fail-under 参数(如工具支持)!! NO 并给出与目标的差距目标:理解项目的设计意图、模块划分和数据流。
格式:
markdown
## 项目理解摘要
### 项目类型
[Web 应用 / API 服务 / CLI 工具 / 库 / ...]
### 模块划分
| 模块 | 职责 | 核心文件 |
|------|------|----------|
### 核心数据流
[描述主要数据流向]
### 外部依赖
[列出所有外部依赖及其用途]
### 业务规则与约束
[从文档中提取的关键业务规则]
详细指南见 design-analysis-guide.md。
使用 AskQuestion 向用户展示项目理解摘要,确认:
用户确认后进入 Phase 2。
目标:从公开 API 的角度理解每个函数的契约,不看实现。
text
禁止读取函数体。只看签名、类型定义、文档注释。
违反这条规则就失去了黑盒视角,测试会不自觉地追随实现细节。
识别公开 API
提取签名信息(仅以下内容)
推断测试维度
对每个函数,基于签名推断: 维度说明正常输入典型合法输入边界值空值、零值、最大/最小值、空集合异常输入类型不匹配、nil/null/undefined、非法格式异常路径基于返回的 error/exception 类型推断并发安全如果签名暗示并发使用(channel、mutex、sync 相关)
产出签名清单
按模块分组,每个函数一行:
markdown
### 模块: [name]
| 函数 | 参数 | 返回值 | 推断的测试维度 |
|------|------|--------|----------------|
| CreateUser | (name string, email string) | (User, error) | 正常/空字符串/重复email/非法格式 |
目标:判断每个函数是否适合直接编写测试,不适合的直接指出设计缺陷。
这是本 skill 的 关键差异化阶段。大多数测试生成工具会为所有函数无脑生成测试, 导致大量 mock 堆砌和脆弱测试。本阶段的职责是 诚实评估。
详细清单和示例见 testability-checklist.md。
核心维度:
维度好的设计坏的设计纯度相同输入 → 相同输出依赖全局状态或隐式输入依赖注入外部依赖通过参数传入函数内部硬编码 new/connect接口隔离参数各自独立,职责清晰God Object 参数,一个 struct 传所有确定性不依赖时间、随机数内部调用 time.Now() 或 Math.random()可观测性行为可通过返回值验证关键行为只通过副作用发生函数粒度单一职责,逻辑聚焦一个函数做五件事
对每个函数给出判定:
可测 (TESTABLE)
需重构 (NEEDS_REFACTOR)
跳过 (SKIP)
markdown
## 可测试性报告
### 统计
- 可测: X 个函数
- 需重构: Y 个函数
- 跳过: Z 个函数
### 需重构的函数
#### [函数名]
- **问题**: [具体的设计缺陷]
- **影响**: [为什么这会导致测试困难]
- **建议**: [具体的重构方向]
### 跳过的函数
| 函数 | 跳过原因 |
|------|----------|
使用 AskQuestion 展示可测试性报告:
目标:为所有"可测"函数生成高质量单元测试,并产出覆盖率报告。
test_<行为>_when_<条件>_should_<预期>确定测试文件位置
*_test.* 或 __tests__/ 目录按模块生成测试
运行测试
生成覆盖率报告
使用项目对应的覆盖率工具(参见 coverage-recipes.md)。
产出摘要(阈值从覆盖率阈值配置中读取): markdown
## 覆盖率报告
### 总体覆盖率
| 指标 | 覆盖率 | 目标 | 达标 |
|------|--------|------|------|
| 行覆盖率 | XX.X% | 80% | YES / !! NO (-X.X%) |
| 分支覆盖率 | XX.X% | 70% | YES / !! NO (-X.X%) |
| 函数覆盖率 | XX.X% | 80% | YES / !! NO (-X.X%) |
### 单文件覆盖率(未达标文件)
| 文件 | 行覆盖率 | 目标 | 差距 |
|------|----------|------|------|
| [仅列出低于 per_file 阈值的文件] |
### 未覆盖的关键路径
[列出仍未覆盖的重要代码路径]
变更行覆盖率(Delta Coverage)
除全量覆盖率外,计算 仅针对本次变更代码 的覆盖率。 这对于"给已有项目补测试"的场景尤为重要 — 关注新增测试是否覆盖了目标代码。
步骤:
git diff 获取相对于基准分支(main/master)的变更行详细工具配方见 coverage-recipes.md 中的"变更行覆盖率"章节。
追加到覆盖率报告中(阈值从 delta 配置读取):
markdown
### 变更行覆盖率(Delta Coverage)
**基准分支**: main
**变更文件数**: N
**变更行数**: M
**目标**: 90%
| 文件 | 变更行 | 已覆盖 | 覆盖率 | 达标 |
|------|--------|--------|--------|------|
**总变更行覆盖率**: XX.X% (目标: 90%) — YES / !! NO
生成 Makefile targets(如项目使用 Makefile)
如果前置检测发现项目有 Makefile,生成测试相关 make targets
( test, test-unit, test-e2e, test-cov, test-cov-delta, test-cov-html)。
生成规则:
COV_LINE ?= 80)使用 AskQuestion 展示:
目标:基于用户故事和数据流,生成端到端集成测试。
识别关键用户路径
基于 Phase 1 的项目理解,识别核心 E2E 场景: 项目类型典型路径Web 应用用户注册 → 登录 → 核心操作 → 验证结果API 服务认证 → CRUD 操作 → 状态验证 → 错误处理CLI 工具参数解析 → 执行 → stdout/stderr 验证 → 退出码库公开 API 的集成调用链
选择 E2E 框架 项目类型推荐框架Web 前端Playwright(首选)/ CypressAPI 服务 (Node)supertestAPI 服务 (Go)net/http/httptestAPI 服务 (Python)httpx + pytestCLI 工具子进程调用 + 断言 stdout/stderr/exit code
生成 E2E 测试
运行 E2E 测试
markdown
## E2E 测试报告
### 测试场景
| 场景 | 覆盖的用户路径 | 状态 |
|------|----------------|------|
### 测试数据管理
[描述 setup/teardown 策略]
生成的测试代码必须满足:
遵循项目已有惯例。如无惯例:单元测试同目录 *_test.*,E2E 测试放 e2e/ 目录。
情况处理方式无设计文档Phase 1 降级为目录结构分析,明确告知用户信息来源无类型信息(纯 JS/Python)Phase 2 从 doc comment 和变量名推断类型函数全部"需重构"暂停流程,给用户一份完整的重构建议清单测试框架未安装提示安装命令,等用户确认后继续覆盖率工具未安装自动检测并提示安装(见前置检测章节),用户确认后安装测试发现被测代码 bug保留失败测试,在报告中标记为"疑似 bug"非 git 仓库跳过变更行覆盖率,仅产出全量覆盖率Makefile 已有同名 target跳过该 target,不覆盖已有配置无 .test-gen.yaml 配置使用默认阈值(80/70/80、60/50、90),告知用户可创建配置文件自定义覆盖率未达标报告中标注差距,不阻塞流程,由用户决定是否补充测试