Install
openclaw skills install gen-test为已有项目生成单元测试和 E2E 测试。分析设计文档和函数签名(黑盒), 评审可测试性设计缺陷,生成测试代码并产出覆盖率报告。 Use when: "generate tests", "add tests", "补测试", "生成单测", "write unit tests", "add e2e tests", "测试覆盖率"。 Proactively suggest when user has an existing project with insufficient test coverage and asks about quality or stability.
openclaw skills install gen-test本 skill 面向代码已存在、需要补充测试的场景(区别于 TDD 先写测试再写代码)。 通过五个阶段,从项目理解到测试交付,系统性地为已有项目生成高质量测试。
核心理念:
支持两种安装方式,使用 AskQuestion 让用户选择:
项目级安装(推荐协作项目,跟随 git 提交,团队共享):
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
用户级安装(个人全局使用,跨项目可用):
mkdir -p ~/.cursor/skills && cp -r /path/to/test-gen ~/.cursor/skills/test-gen
项目级安装的 skill 优先于用户级。如果两处都存在,项目级生效。 用户级安装时不支持斜杠命令(命令只能放在项目的
.cursor/commands/下)。
在开始前,自动检测项目环境:
检测清单:
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-cov | pip install pytest-cov |
| JS/TS (Jest) | 无 --coverage 配置 | 已内置,无需安装 |
| JS/TS (Vitest) | 无 @vitest/coverage-* | npm install -D @vitest/coverage-v8 |
| Go | — | 内置 go test -cover,无需安装 |
| Rust | 无 cargo-tarpaulin/llvm-cov | cargo install cargo-llvm-cov |
| Java (Maven) | 无 JaCoCo 插件 | 在 pom.xml 中添加 JaCoCo 插件配置 |
| Java (Gradle) | 无 jacoco 插件 | 在 build.gradle 中添加 id 'jacoco' |
| C#/.NET | 无 coverlet | dotnet add package coverlet.collector |
安装前使用 AskQuestion 确认:
检测到项目缺少覆盖率工具。建议安装:
- [工具名] (安装命令: `xxx`)
是否立即安装?
详细的安装配方见 coverage-recipes.md。
将检测结果汇报给用户,确认无误后进入覆盖率阈值加载。
在前置检测完成后、进入 Phase 1 之前,加载覆盖率阈值。
三层阈值,各自独立判定:
coverage_thresholds:
overall: # 全项目总体阈值
line: 80 # 行覆盖率 %
branch: 70 # 分支覆盖率 %
function: 80 # 函数覆盖率 %
per_file: # 单文件阈值(任何单文件不低于此值)
line: 60
branch: 50
delta: # 变更行覆盖率阈值
line: 90 # 新增/修改的代码行覆盖率
按顺序查找,找到即停:
项目配置文件 .test-gen.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 并给出与目标的差距目标:理解项目的设计意图、模块划分和数据流。
搜索设计文档
提取关键信息
无文档时的降级策略
产出项目理解摘要
格式:
## 项目理解摘要
### 项目类型
[Web 应用 / API 服务 / CLI 工具 / 库 / ...]
### 模块划分
| 模块 | 职责 | 核心文件 |
|------|------|----------|
### 核心数据流
[描述主要数据流向]
### 外部依赖
[列出所有外部依赖及其用途]
### 业务规则与约束
[从文档中提取的关键业务规则]
详细指南见 design-analysis-guide.md。
使用 AskQuestion 向用户展示项目理解摘要,确认:
用户确认后进入 Phase 2。
目标:从公开 API 的角度理解每个函数的契约,不看实现。
禁止读取函数体。只看签名、类型定义、文档注释。
违反这条规则就失去了黑盒视角,测试会不自觉地追随实现细节。
识别公开 API
提取签名信息(仅以下内容)
推断测试维度
对每个函数,基于签名推断:
| 维度 | 说明 |
|---|---|
| 正常输入 | 典型合法输入 |
| 边界值 | 空值、零值、最大/最小值、空集合 |
| 异常输入 | 类型不匹配、nil/null/undefined、非法格式 |
| 异常路径 | 基于返回的 error/exception 类型推断 |
| 并发安全 | 如果签名暗示并发使用(channel、mutex、sync 相关) |
产出签名清单
按模块分组,每个函数一行:
### 模块: [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)
## 可测试性报告
### 统计
- 可测: X 个函数
- 需重构: Y 个函数
- 跳过: Z 个函数
### 需重构的函数
#### [函数名]
- **问题**: [具体的设计缺陷]
- **影响**: [为什么这会导致测试困难]
- **建议**: [具体的重构方向]
### 跳过的函数
| 函数 | 跳过原因 |
|------|----------|
使用 AskQuestion 展示可测试性报告:
目标:为所有"可测"函数生成高质量单元测试,并产出覆盖率报告。
test_<行为>_when_<条件>_should_<预期>确定测试文件位置
*_test.* 或 __tests__/ 目录按模块生成测试
运行测试
生成覆盖率报告
使用项目对应的覆盖率工具(参见 coverage-recipes.md)。
产出摘要(阈值从覆盖率阈值配置中读取):
## 覆盖率报告
### 总体覆盖率
| 指标 | 覆盖率 | 目标 | 达标 |
|------|--------|------|------|
| 行覆盖率 | 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 配置读取):
### 变更行覆盖率(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(首选)/ Cypress |
| API 服务 (Node) | supertest |
| API 服务 (Go) | net/http/httptest |
| API 服务 (Python) | httpx + pytest |
| CLI 工具 | 子进程调用 + 断言 stdout/stderr/exit code |
生成 E2E 测试
运行 E2E 测试
## 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),告知用户可创建配置文件自定义 |
| 覆盖率未达标 | 报告中标注差距,不阻塞流程,由用户决定是否补充测试 |