mcpField
G
gen-test-plan

gen-test-plan

github.com/existential-birds测试与质量8568 次安装11 周前更新
代码仓库

关于 gen-test-plan

gen-test-plan 是分析仓库技术栈与分支变更并生成可执行 YAML 端到端测试计划的技能。它聚焦用户可见行为,并明确避免重复运行自动化测试套件。

主要功能

  1. 01分析技术栈与分支变更
  2. 02追踪变更影响的用户入口
  3. 03区分核心功能与配置入口
  4. 04生成 YAML 端到端测试计划
  5. 05验证覆盖度并排除测试运行器步骤

适用场景

  1. 01为分支变更制定 QA 计划
  2. 02通过真实交互测试变更后的 CLI 或 API
  3. 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. 固定差异和基准(步骤 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(允许列表为空,但必须粘贴或引用该命令的输出,并注明“相对于基准分支没有文件变更”)。

  2. 追踪完整(步骤 4 之后)——通过:你将测试的每个受影响入口点都已分类为核心功能或配置/管理,并满足步骤 4 的要求:至少有一个测试针对核心入口点,或者记录无法做到这一点的原因并标记为需要人工审查。

  3. 计划文件有效(步骤 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)"
    
  4. 不得重复执行自动化测试(步骤 8)——通过:检查每个 run: 步骤和每个 services: 的 command:,确认其中没有项目测试运行器(cargo test、pytest、npm test、go test、mix test、jest、vitest、mocha 等);调用次数为零。如果发现任何调用,请删除或替换为真实的 E2E 操作,然后重新运行关卡 3。

  5. 行为覆盖(步骤 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:追踪变更对入口点的影响

对于每个已更改文件,确定它是否会影响面向用户的功能:

  1. 直接入口点变更 — 文件包含路由定义
  2. 导入链分析 — 查找导入已更改文件的内容,并沿链向上追踪至入口点
  3. 结合架构进行追踪 — 阅读项目的 CLAUDE.md、README 或架构文档,了解数据流和模块关系,而非仅依赖 grep
  4. 在测试上下文中记录追踪路径
按生态系统进行导入链分析
# 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-browser CLI 命令(例如 agent-browser open、agent-browser snapshot -i、agent-browser click @ref)——绝不使用抽象的操作语法
  • 与元素交互前以及导航/DOM 变更后,始终运行 agent-browser snapshot -i
  • 使用 agent-browser screenshot <path> 为浏览器测试截取证据
  • 密钥使用 ${ENV_VAR} 语法,绝不硬编码凭据
  • 如果未检测到面向用户的变更,请说明原因并建议手动验证

评论

支持 Markdown