关于 gen-test-plan
gen-test-plan 是分析仓库技术栈与分支变更并生成可执行 YAML 端到端测试计划的技能。它聚焦用户可见行为,并明确避免重复运行自动化测试套件。
主要功能
- 01分析技术栈与分支变更
- 02追踪变更影响的用户入口
- 03区分核心功能与配置入口
- 04生成 YAML 端到端测试计划
- 05验证覆盖度并排除测试运行器步骤
适用场景
- 01为分支变更制定 QA 计划
- 02通过真实交互测试变更后的 CLI 或 API
- 03检查用户可见功能的测试覆盖
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ existential-birds/ beagle --skill gen-test-plan安装后在 Claude Code 中输入/gen-test-plan确认已加载。
附带文件references/stack-discovery.mdreferences/test-case-generation.md
详细介绍
生成测试计划
分析仓库的技术栈、当前分支相对于默认分支的变更,并生成一份可执行的 YAML 测试计划,重点关注用户可见的影响。
这是 E2E 测试计划,而不是自动化测试封装。 生成的计划将由自主 Agent 执行,其行为与人工 QA 测试人员完全一致:启动真实二进制文件、访问真实端点、与真实数据库交互,并验证实际可观察到的行为。
关键规则:不得重复执行自动化测试
**绝不要生成会重新运行项目现有自动化测试套件的测试步骤。**这意味着:
- 不得将
cargo test、pytest、npm test、go test、mix test或等效命令作为测试步骤 - 不得将单元测试或集成测试模块包装在测试用例中
- 不得写“运行测试并检查是否通过”——这是 CI 的工作,不是 QA 的工作
如果你发现自己写了一个会调用项目测试运行器的测试步骤,请停下来重新考虑。问问自己:“人工测试人员会怎样验证此功能正常工作?”答案绝不会是“运行单元测试”。
E2E 测试步骤示例:
- 构建二进制文件,使用真实参数运行,并检查 stdout/stderr/退出代码
- 启动服务并使用 curl 访问
- 运行会向真实数据库写入数据的 CLI 命令,然后查询数据库进行验证
- 启动 TUI 并验证其是否正常呈现(通过截图或进程生命周期)
- 串联多个命令,端到端地执行完整用户工作流
硬性关卡
请按顺序完成这些关卡。只有满足当前关卡的通过条件后,才能进入下一关(每次通过都应留下可供检索的证据:粘贴的命令输出、书面列表或已生成的文件)。**安排顺序:**步骤 2 之前完成关卡 1;步骤 5 之前完成关卡 2;步骤 7 之前完成关卡 3;步骤 8 期间(步骤 7 总结之后)完成关卡 4–5。
-
固定差异和基准(步骤 1 之后)——如果提供了
--base,则据此解析基准分支;否则使用仓库默认分支(按步骤 1 确定为main或master)。比较HEAD与$(git merge-base HEAD origin/<base_branch>)(如果远程引用不同,也可使用等效方式)。**通过:**记录current_branch、base_branch、使用的 merge-base SHA 或范围,以及通过git diff --name-only <merge-base>..HEAD得到的changed_files(允许列表为空,但必须粘贴或引用该命令的输出,并注明“相对于基准分支没有文件变更”)。 -
追踪完整(步骤 4 之后)——通过:你将测试的每个受影响入口点都已分类为核心功能或配置/管理,并满足步骤 4 的要求:至少有一个测试针对核心入口点,或者记录无法做到这一点的原因并标记为需要人工审查。
-
计划文件有效(步骤 6 之后、步骤 7 之前)——
docs/testing/test-plan.yaml已存在,且以下命令退出代码为 0(解析 YAML 并断言存在全部四个顶层键——单个带交替项的grep -E只要匹配任意一项就会通过,因此不得用它替代):python3 -c "import sys, yaml; d = yaml.safe_load(open('docs/testing/test-plan.yaml')) or {}; missing = [k for k in ('version', 'metadata', 'setup', 'tests') if k not in d]; sys.exit('Missing keys: ' + ', '.join(missing) if missing else 0)" -
不得重复执行自动化测试(步骤 8)——通过:检查每个
run:步骤和每个services:的command:,确认其中没有项目测试运行器(cargo test、pytest、npm test、go test、mix test、jest、vitest、mocha等);调用次数为零。如果发现任何调用,请删除或替换为真实的 E2E 操作,然后重新运行关卡 3。 -
行为覆盖(步骤 8)——**通过:**重新阅读
metadata.changes_summary和近期提交消息;至少有一项测试的context/steps能够测试其中描述的主要用户可见行为。如果描述了某项能力(例如新增 provider),但没有步骤调用该能力,则添加该测试,否则验证不通过。
参数
--base <branch>:用于比较差异的基准分支(默认:main)- 路径:目标目录(默认:当前工作目录)
步骤 1:收集仓库上下文
# Get current branch
git rev-parse --abbrev-ref HEAD
# Resolve base branch: use --base if supplied, otherwise default (main → master)
BASE_BRANCH="${BASE_BRANCH:-$(git rev-parse --verify origin/main >/dev/null 2>&1 && echo main || echo master)}"
MERGE_BASE="$(git merge-base HEAD "origin/${BASE_BRANCH}")"
# Get changed files vs base
git diff --name-only "${MERGE_BASE}"..HEAD
# Get commit messages for context
git log --oneline "${MERGE_BASE}"..HEAD
记录:
current_branch:分支名称base_branch:用于比较的默认分支changed_files:已修改文件列表commit_messages:PR 的内容
步骤 2:检测技术栈
有关技术栈检测命令、入口点发现、端口发现和追踪规则,请参阅 references/stack-discovery.md。
步骤 3:发现面向用户的入口点
“面向用户的入口点”是指人类会与之交互的任何内容:CLI 子命令、HTTP 端点、UI 路由、TUI 屏幕、gRPC 服务、数据库迁移,或会影响运行时行为的配置文件。
CLI 应用(Rust/clap、Python/argparse/click、Go/cobra)
# Rust (clap) — look for Subcommand derives and command enums
grep -rn "Subcommand\|#\[command\]" --include="*.rs" | head -20
# Python (click/typer/argparse)
grep -rn "@click.command\|@app.command\|add_parser\|add_subparser" --include="*.py" | head -20
# Go (cobra)
grep -rn "cobra.Command\|AddCommand" --include="*.go" | head -20
建立以下信息的映射:
- CLI 子命令:命令名称 + 描述 + 文件:行号
- 每个子命令的必需参数和标志
- 二进制程序读取的环境变量(搜索
env、std::env::var、os.Getenv、os.environ)
HTTP/API 服务
Python(FastAPI/Flask):
grep -rn "@app\.\(get\|post\|put\|delete\|patch\)" --include="*.py" | head -20
grep -rn "@router\.\(get\|post\|put\|delete\|patch\)" --include="*.py" | head -20
Node.js(Express/Fastify):
grep -rn "app\.\(get\|post\|put\|delete\)" --include="*.ts" --include="*.js" | head -20
grep -rn "router\.\(get\|post\|put\|delete\)" --include="*.ts" --include="*.js" | head -20
Rust(axum/actix/rocket):
grep -rn "Router::new\|\.route(\|#\[get\]\|#\[post\]\|HttpServer" --include="*.rs" | head -20
Go(net/http、gin、chi):
grep -rn "http.HandleFunc\|r.GET\|r.POST\|router.Get\|router.Post" --include="*.go" | head -20
Elixir(Phoenix):
grep -rn "get \"/\|post \"/\|pipe_through\|live \"/\|scope \"/\"" --include="*.ex" | head -20
浏览器 UI 路由
grep -rn "createBrowserRouter\|<Route\|path=" --include="*.tsx" --include="*.jsx" | head -20
数据库与迁移
# SQL migrations
ls migrations/ db/migrate/ priv/repo/migrations/ 2>/dev/null
# Schema files
ls schema.sql schema.prisma 2>/dev/null
建立整合映射,包含:
- CLI 子命令:名称 + 参数 + 文件:行号
- API 端点:方法 + 路径 + 文件:行号
- UI 路由:路径 + 组件 + 文件:行号
- 数据库迁移:文件名 + 创建/更改内容
- 配置:会影响行为的环境变量和配置文件
步骤 4:追踪变更对入口点的影响
对于每个已更改文件,确定它是否会影响面向用户的功能:
- 直接入口点变更 — 文件包含路由定义
- 导入链分析 — 查找导入已更改文件的内容,并沿链向上追踪至入口点
- 结合架构进行追踪 — 阅读项目的 CLAUDE.md、README 或架构文档,了解数据流和模块关系,而非仅依赖 grep
- 在测试上下文中记录追踪路径
按生态系统进行导入链分析
# Rust — use/mod/crate references and workspace deps
grep -rn "use.*<crate>\|mod <module>" --include="*.rs"
grep -rn "<crate-name>" --include="Cargo.toml"
# Python — from/import
grep -rn "from.*<module>\|import.*<module>" --include="*.py"
# TypeScript/JavaScript — import/require
grep -rn "from.*<module>\|require.*<module>" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx"
# Elixir — alias/import/use
grep -rn "alias.*<Module>\|import.*<Module>\|use.*<Module>" --include="*.ex" --include="*.exs"
# Go — package references
grep -rn "<package>\." --include="*.go"
如果上文未涵盖该生态系统,或者 grep 结果不明确,请阅读项目的 CLAUDE.md、README 或架构文档,了解模块图,并追踪从已更改文件到面向用户入口点的数据流。
对受影响的入口点进行分类
识别出所有受影响的入口点后,逐一分类:
| 类别 | 说明 | 示例 | 优先级 |
|---|---|---|---|
| 核心功能 | 功能实际为最终用户执行工作的入口点 | 聊天端点、API 操作、数据处理流水线、生成流程 | 高 — 优先测试 |
| 配置/管理 | 用于设置、切换或配置功能的入口点 | 设置页面、管理仪表板、偏好设置开关、下拉选项 | 较低 — 核心功能之后测试 |
分类规则:
- 思考:“如果用户想要使用此功能(而非配置它),会与哪个入口点交互?”——这就是核心功能
- 添加了新下拉选项的设置页面属于配置;实际使用该选项的端点属于核心功能
- 同一个已更改文件(例如,新增的提供程序模块)可能同时影响设置页面和功能端点——必须追踪两者
要求: 生成配置/管理测试之前,至少必须有一项测试针对核心功能入口点。如果无法识别核心功能入口点,必须明确记录原因,并标记为需要人工审查。
输出: 针对每个受影响的入口点,记录:
- 哪些已更改文件会影响它
- 导入/依赖链
- **分类:**核心功能或配置/管理
- 此入口点需要测试的原因
第 5 步:生成测试用例
详细的 API/浏览器模板、优先级规则和测试用例指南,请参阅 references/test-case-generation.md。
第 6 步:编写 YAML 测试计划
创建测试计划文件:
mkdir -p docs/testing
写入 docs/testing/test-plan.yaml:
version: 1
metadata:
branch: <current_branch>
base: <base_branch>
generated: <ISO timestamp>
changes_summary: |
<Summary of what this PR changes based on commit messages and diff>
setup:
stack:
- type: <rust|node|python|go|elixir|docker>
package_manager: <cargo|pnpm|npm|yarn|uv|poetry|mix|none>
prerequisites:
# Services or infrastructure the tests need running
- name: <e.g., PostgreSQL>
check: <command to verify it's available, e.g., "pg_isready -h localhost">
build:
# Commands to build the project artifacts (binaries, assets, etc.)
- <build command, e.g., "cargo build --workspace">
services:
# Long-running processes to start before tests (servers, watchers, etc.)
# Omit if the project is a CLI tool or library with no server component
- command: <start command>
health_check:
url: http://localhost:<port>/health
timeout: 30
env:
# Environment variables needed by tests (use ${VAR} for secrets)
DATABASE_URL: "${DATABASE_URL}"
tests:
# CLI test example — run the built binary with real arguments:
- id: TC-01
name: <CLI test name>
context: |
<Why this test exists, which changes affect it>
steps:
- run: <command that a human would type in their terminal>
- run: <follow-up command to verify the effect>
expected: |
<Expected behavior: exit code, stdout content, side effects>
# API test example:
- id: TC-02
name: <API test name>
context: |
<Why this test exists, which changes affect it>
steps:
- action: curl
method: GET
url: http://localhost:<port>/<path>
expected: |
<Expected behavior in natural language>
# Database verification example:
- id: TC-03
name: <Database test name>
context: |
<Why this test exists, which changes affect it>
steps:
- run: <command that writes to the database>
- run: psql "${DATABASE_URL}" -c "SELECT ... FROM ... WHERE ..."
expected: |
<Expected rows, schema state, or migration effect>
# Browser test example (always use agent-browser CLI commands):
- id: TC-04
name: <UI test name>
context: |
<Why this test exists, which changes affect it>
steps:
- run: agent-browser open http://localhost:<port>/<path>
- run: agent-browser snapshot -i
- run: agent-browser click @<ref>
- run: agent-browser snapshot -i
- run: agent-browser screenshot evidence/tc-04.png
expected: |
<Expected behavior in natural language>
evidence:
screenshot: evidence/tc-04.png
第 7 步:报告摘要
生成测试计划后:
## Test Plan Generated
**File:** `docs/testing/test-plan.yaml`
**Branch:** <current_branch> → <base_branch>
### Detected Stack
| Component | Type | Port |
|-----------|------|------|
| <component> | <type> | <port> |
### Tests Generated
| ID | Name | Type | Affected By |
|----|------|------|-------------|
| TC-01 | <name> | curl/browser | <files> |
### Entry Point Coverage
- **Covered:** <N> entry points with tests
- **Unchanged:** <M> entry points not affected by this PR
### Next Steps
1. Review the generated test plan at `docs/testing/test-plan.yaml`
2. Adjust test values and expectations as needed
3. Run the tests by invoking the **run-test-plan** skill ([run-test-plan](../run-test-plan/SKILL.md))
第 8 步:验证
在将计划视为已完成之前,请根据证据确认已满足 硬性门槛 1–5(参见上文的 硬性门槛)。然后运行:
# Verify file was created
ls -la docs/testing/test-plan.yaml
# Validate YAML syntax
python3 -c "import yaml; yaml.safe_load(open('docs/testing/test-plan.yaml'))" && echo "Valid YAML"
# Check required fields
grep -E "^version:|^metadata:|^setup:|^tests:" docs/testing/test-plan.yaml
验证清单:
- 已在
docs/testing/test-plan.yaml创建测试计划文件 - YAML 语法有效
- 至少生成了一个测试用例
- 设置命令与检测到的技术栈相符
- 每个测试都有 id、name、steps 和 expected 字段
- 不得重复执行自动化测试: 对计划中每个
run:和command:步骤进行 grep,检查其中是否调用了测试运行器(cargo test、pytest、npm test、go test、mix test、jest、vitest、mocha等)。如果任何步骤调用了项目的测试运行器,计划将无法通过验证。移除这些步骤,并替换为真实的 E2E 操作。 - 行为覆盖: 至少有一个测试覆盖
changes_summary中描述的主要行为变更。重新阅读changes_summary和提交消息——如果其中描述了某项能力(例如“新增 LLM 提供方”),但没有测试调用该能力(例如通过该提供方发送消息),计划将无法通过验证。完成前请补充缺失的核心功能测试。 - 不得仅包含配置测试的计划: 如果所有测试都针对配置/管理入口,而没有任何测试针对核心功能入口,计划就不完整。返回第 4 步,找出核心功能入口,并为其添加测试。
规则
- 仅限 E2E——每个测试步骤都必须像人类用户一样操作真实构建产物(二进制文件、服务、UI)。绝不要封装自动化测试套件。
- 如果
docs/testing/目录不存在,始终创建该目录 - 为每个受影响的入口点至少生成一个测试
- 添加上下文,说明每个测试的重要性(追溯到具体变更)
expected字段使用自然语言(由 Agent 解读)- CLI 项目: 测试步骤应使用真实参数调用实际二进制文件,并验证 stdout、stderr、退出代码和副作用(创建的文件、写入的数据库行、启动的进程)
- 服务项目: 在设置阶段启动服务,通过 curl/agent-browser 进行测试
- 仅包含库且没有二进制文件或服务的项目: 如果变更纯粹涉及内部库代码,且没有面向用户的入口(无 CLI、无服务、无 UI),请明确说明这一点,并生成通过小型驱动脚本调用公开 API 来测试库的用例——而不是运行测试套件
- 端口检测默认采用保守值(API 使用 8000,前端使用 5173/3000)
- 浏览器自动化步骤必须使用
agent-browserCLI 命令(例如agent-browser open、agent-browser snapshot -i、agent-browser click @ref)——绝不使用抽象的操作语法 - 与元素交互前以及导航/DOM 变更后,始终运行
agent-browser snapshot -i - 使用
agent-browser screenshot <path>为浏览器测试截取证据 - 密钥使用
${ENV_VAR}语法,绝不硬编码凭据 - 如果未检测到面向用户的变更,请说明原因并建议手动验证