mcpField
A
ai-test-generation

ai-test-generation

github.com/petrkindlmann测试与质量2221.2k 次安装6 天前更新
代码仓库

关于 ai-test-generation

面向测试团队的 AI 测试生成技能,通过结构化流程把需求转化为可审查的测试。它先形成风险分析、覆盖矩阵和断言预言机,再生成代码并要求人工审核。

主要功能

  1. 01从需求、缺陷或代码提取规则
  2. 02分析风险、不变量与歧义
  3. 03建立需求到场景的覆盖矩阵
  4. 04将测试场景与断言设计分开
  5. 05生成可追溯的测试代码
  6. 06要求人工审查生成结果

适用场景

  1. 01根据 PRD 或用户故事规划测试
  2. 02针对代码变更生成回归场景
  3. 03为缺陷报告编写验证测试
  4. 04从 API 模式设计覆盖场景

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/petrkindlmann/qa-skills --skill ai-test-generation

安装后在 Claude Code 中输入/ai-test-generation确认已加载。

附带文件references/prompt-patterns.md

详细介绍

LLM 会轻松生成 50 个看起来合理、却没有断言任何内容的测试;这些测试可能针对根本不存在的端点,还可能彼此重复。这项技能采用分阶段流水线,强制模型在编写任何测试代码之前,先生成结构化中间产物——假设、覆盖矩阵、预言定义——让最终结果可追溯、可审查,并以真实代码库为依据,而不是随意生成一堆噪声。

**开始之前:**检查项目根目录下是否有 .agents/qa-project-context.md。该文件包含技术栈、测试框架、命名约定、选择器策略和已知风险区域,可显著提升生成测试的质量。

快速路径

无论输入是什么,流水线都相同;只有第 1 步提取的重点会改变。找到匹配的行,然后保持不变地执行第 2 至第 7 步。

输入类型第 1 步提取内容注意事项
PRD / 功能规格实体、业务规则、验收标准、NFR、明确说明的假设从“无缝”“快速”等措辞中推断出的隐含需求
用户故事 + AC每条 AC → ≥1 个正常场景 + ≥1 个异常场景一行 AC 中隐含多种行为的情况
代码差异(git diff main...HEAD)新增/变更的代码路径、修改的条件判断、移除的行为回归范围:测试变更的路径,而不是整个模块
Bug 报告复现步骤、预期结果与实际结果、环境编写断言预期结果的测试——当前会失败,修复后会通过
OpenAPI / GraphQL SDL端点、架构、必填字段、枚举、身份验证每个端点都覆盖验证、身份验证失败和边缘情况,而不只是 200 响应

Playwright 项目还需选择 Agent 集成模式——参见“探索问题”中的问题 2。

探索问题

先检查 .agents/qa-project-context.md——如果文件存在,请使用其中的信息,并跳过已得到解答的问题。然后澄清以下事项:

  1. **输入来源是什么?**PRD / 规格、用户故事 + AC、代码差异、Bug 报告或 API 架构。这决定了第 1 步提取的重点(参见“快速路径”)。对于 LLM/AI 功能规格,请停止——应在 ai-system-testing 中生成评估数据集,而不是 Playwright 规格。

  2. 目标测试框架是什么?(如果使用 Playwright)应采用哪种 Agent 集成模式?

    • **端到端测试:**Playwright(首选)、Cypress。**单元测试:**Jest、Vitest、pytest。**API 测试:**Playwright APIRequestContext、Supertest、requests。
    • Playwright CLI + agents(推荐用于 Claude Code / Codex / Cursor):npx playwright init-agents --loop=claude 会将规划、生成和修复 Agent 脚手架生成为 .claude/agents/ 中的 Markdown 文件。这些是交互式开发工具,可生成在 CI 中无需修改即可运行的标准 Playwright 测试。可节省 Token;在 Agent 的循环中运行。
    • Playwright MCP(npx @playwright/mcp@latest):开销较高,但适用于 Agent 必须在长时间会话中交互式操控实时浏览器的情况。
    • 两者都不用——使用 AI 作为草稿助手,手动编写测试。
  3. **有哪些项目上下文可用?**现有测试模式、Page Object / 助手、数据工厂 / 固件、CI 限制(超时、并行度)。上下文越充分,后续清理工作越少。

  4. **审查工作流是什么?**完整流水线 → 人工审查 → 合并(默认);仅生成场景 → 人工编写代码;或先生成代码 → 人工迭代完善。

  5. **需要哪些领域知识?**受监管行业(医疗保健、金融)的合规要求、领域不变量(金额不得为负、预约不得重叠)、过去事件中已知的风险区域。

核心原则

  1. 先规划流水线,再编写代码。 在明确测试什么、为什么测试以及如何验证之前,绝不生成测试代码。七步流水线旨在防止过早生成代码,以免测试错了对象。

  2. 结构化中间产物才是核心成果。 假设文档、覆盖矩阵和判定依据定义比测试代码本身更有价值。它们可供审查、可追溯且可复用。

  3. 将测试内容与验证方式分开。 场景生成(测试什么)和判定依据设计(如何验证)是两项不同的认知任务。将两者混在一起,会让场景偏向容易断言的内容,并把断言当作事后补充。

  4. AI 生成初稿;由人工审查和完善。 绝不在未经人工审查的情况下发布 AI 生成的测试。AI 能加快进度,但不能取代判断。

  5. 上下文至关重要。 向大模型提供你的约定、现有模式、选择器策略和数据设置。上下文越充分,后续清理工作就越少。

  6. 质量胜于数量。 每项测试都有维护成本。应聚焦关键路径、复杂逻辑和已知风险区域,而不是测试数量。

流水线

强制工作流 — Agent 必须按以下顺序执行:

Step 1: Extract   → Requirements, entities, business rules from input
Step 2: Analyze   → Risks, invariants, edge cases, ambiguities
Step 3: Map       → Coverage matrix (requirement → scenario → priority)
Step 4: Generate  → Candidate scenarios (happy + boundary + negative + security + a11y)
Step 5: Design    → Assertions and oracles SEPARATELY from scenarios
Step 6: Code      → Test code (only after all above exist)
Step 7: Review    → Human review with traceability back to source

每个步骤(提取、风险分析、场景、判定依据、代码)的完整提示词模板都位于 references/prompt-patterns.md。以下说明各步骤输出的形式。

步骤 1:提取需求和实体

将输入解析为结构化元素:实体(包含角色/状态/属性)、业务规则(编号)、显式需求([REQ-N],在源材料中明确说明)和隐式需求([IMP-N],推断得出——每一项都要标记,供人工确认)。将显式需求与推断需求分开,是防止把假设当成规范进行测试的关键。

步骤 2:风险分析与不变量

推导可能出错的情况、必须始终成立的条件,以及源材料未明确说明的部分。

  • 风险 — 表格列为 Risk | Likelihood | Impact | Source Requirement(例如,库存扣减时发生竞态条件、邮件延迟超过 30s)。
  • 不变量(必须始终成立)— stock >= 0、order total = sum(items) + tax + shipping、user sees only their own orders。
  • 歧义(需要人工答复)—“免运费是在应用折扣码之前还是之后生效?”明确记录这些问题;不要默默自行选择。
  • 从风险推导的边界情况 — 两个用户同时购买最后一件商品;付款成功,但邮件服务不可用。
步骤 3:覆盖矩阵

这是最重要的单一产物,可防止遗漏和重复。将每项需求映射到场景,并标明类别、优先级和判定依据类型:

RequirementScenarioCategoryPriorityOracle Type
REQ-1将单件商品添加到空购物车Happy pathP0State: cart count = 1
REQ-1添加缺货商品NegativeP0UI: error message, cart unchanged
REQ-2使用有效银行卡完成结账Happy pathP0State: order created, stock decremented
REQ-2两个用户同时结账购买最后一件商品Race conditionP1一人成功,另一人收到库存错误
INV-1库存绝不为负数InvariantP0Data: stock >= 0 after any operation

完成后,进行验证:每项需求至少有 1 个正常场景和 1 个负向场景;每个不变量都有直接测试;步骤 2 中的每项风险都有对应场景;没有两行测试相同内容。

步骤 4:生成候选场景

针对矩阵中的每一行,使用 Given/When/Then 格式编写完整场景,并明确测试数据要求(Given: 用户购物车中有 99 件商品(上限为 100 件);When: 再添加一件;Then: 数量 = 100)。系统地覆盖以下类别:

类别描述
正常路径用户严格按照功能设计的方式操作
边界有效输入范围的边缘——使用 BOUNDARIES 框架(references/prompt-patterns.md)
负面无效输入、未经授权的操作
安全绕过身份验证、注入、权限提升
无障碍屏幕阅读器、仅使用键盘、对比度
状态转换状态之间的有效和无效转换
并发两个用户同时操作
步骤 5:设计断言与判定依据

与步骤 4 刻意分开。 场景描述行为;判定依据描述如何验证行为。针对每个场景,定义涵盖以下类别的判定依据——单条断言很少足以证明某个行为:

判定依据类别断言内容示例
UI 状态可见文本/元素状态cart badge toHaveText('1')
数据通过 API/数据库持久化的状态GET /api/cart 返回 1 件商品,且总额正确
负面不应发生的情况无错误提示;未跳转离开当前页面
副作用异步/外部结果触发 analytics add_to_cart;< 30 秒内邮件进入收件箱

**判定依据质量规则:**断言业务结果,而不是实现细节;使用最具体的可用断言(toHaveText('$29.99'),而不是 toBeTruthy());加入负面断言;验证数据完整性,而不仅仅是 UI;断言无障碍特性(焦点管理、实时区域播报)。

步骤 6:生成测试代码

仅在步骤 1-5 产出经过审查的工件后执行。 代码是将场景和判定依据机械地转换为框架语法,并附上追溯注释,将测试关联到需求和场景:

/**
 * Scenario: SC-001 — Add single item to empty cart
 * Requirement: REQ-1 (User can add items to cart)
 * Priority: P0
 */
test('add single item to empty cart', async ({ page, testProduct }) => {
  await page.goto(`/products/${testProduct.id}`);                       // Given
  await page.getByRole('button', { name: 'Add to cart' }).click();      // When
  await expect(page.getByTestId('cart-badge')).toHaveText('1');         // Then
  await expect(page.getByTestId('error-toast')).not.toBeVisible();      // Negative oracle
});

**代码生成规则:**遵循项目约定(来自 qa-project-context.md);复用现有 Page Objects、夹具和数据工厂;添加追溯注释(Scenario: SC-XXX、Requirement: REQ-XX);遵循项目的选择器策略;将设置/清理操作放在夹具中,而不是内联编写。

步骤 7:人工审查

此步骤不可省略——这是必需的流水线步骤。审查此流水线刚刚生成的测试,并在合并前完成。(如需审查并非由此流水线刚生成的现有测试套件,请改用 ai-qa-review。)根据此清单逐一检查生成的测试:

  • **可追溯到需求:**测试 → 场景 → 覆盖矩阵行 → 需求的关联链清晰可循。
  • **测试行为,而非实现:**无害的重构不会导致测试失败。
  • **抽象层级正确:**测试类型合适(单元测试、集成测试或 E2E 测试)。
  • **测试命名与可读性:**测试名称说明了所测行为;读者无需解读测试正文即可理解意图。
  • **测试隔离/无共享状态:**测试创建并清理自己的数据,不依赖同组测试的执行顺序,并且单独运行或按任意顺序运行都能通过。
  • **测试数据真实:**数据合理、多样,并使用 example.com。
  • **断言有意义:**与判定依据的定义一致;具体明确,而非 toBeTruthy()。
  • **符合项目约定:**遵循命名、结构和选择器策略。
  • **无不稳定性风险:**没有硬编码超时、竞态条件或顺序依赖。
  • **包含边缘情况:**不局限于正常路径。
  • **假设已验证:**步骤 2 中的模糊之处已在编码前解决。

**每项测试的审查结果:**保留(原样合并)· 修改(修复列出的问题后合并)· 拒绝(需求错误、抽象层级错误、虚构 API)· 暂缓(受模糊之处阻碍)。

护栏

硬性规则。Agent 必须遵守。

  • 禁止先写代码再补覆盖。 在步骤 1-3(需求、含书面假设的风险分析、覆盖矩阵)完成之前,绝不编写测试代码。如果 Agent 跳过这些步骤直接写代码:立即停止,返回前面的步骤。
  • 断言结果,而非实现。 使用 expect(screen.getByRole('progressbar')).toBeVisible(),而不是 expect(component.state.isLoading).toBe(true)。使用 expect(page.getByTestId('cart-badge')).toHaveText('1'),而不是 expect(store.dispatch).toHaveBeenCalledWith(...)。
  • 始终先写场景(步骤 4),再写预期结果(步骤 5)。 场景说明发生了什么;预期结果说明如何验证。将二者混在一起,会使场景偏向容易断言的内容。
  • 始终产出中间成果——假设文档、未解决的歧义、预期结果候选项和可追溯链,即使是简略版本也不例外。

发现以下情况时请标记:

  • 臆造的 API——代码库中不存在的端点、选择器、方法或导入项。在人工审查前进行机械验证(参见“验证”)。
  • 重复场景——相同行为仅使用了略有不同的数据。合并或参数化。
  • 低价值断言——expect(response).toBeTruthy()、expect(page).toHaveURL(/.*/).
  • 缺少负面用例——如果所有场景都是成功路径,覆盖矩阵就不完整。
  • 不真实的测试数据——[email protected]、John Doe、password123。请使用多样、可信的数据,并采用 example.com 域名。

各步骤的模型选择

按难度选择模型,而非凭习惯。机械式提取(步骤 1)和覆盖矩阵整理(步骤 3)使用低成本模型即可——Haiku 4.5 或 Sonnet 4.6 已足够。预期结果设计(步骤 5)和对臆造内容敏感的代码生成(步骤 6)出错代价较高,应升级到 Opus 4.8;只有面对真正困难的推理问题(微妙的不变量、受监管领域的逻辑)时,才使用 Fable 5。每一步都运行最强模型很浪费;步骤 6 使用最便宜的模型则会导致编造 API。

验证

将“臆造的 API”警告转化为机械检查关卡。在步骤 6 完成后、人工审查前:

  1. 解析导入项 / 类型。 TypeScript:npx tsc --noEmit——臆造的导入项和错误的签名都会在此处报错。Python:python -m pyflakes <files> 或 ruff check。
  2. 使用 grep 对照代码库检查生成的选择器 / 端点。 确认每个 getByTestId('...') 中的 ID,以及测试调用的每个 API 路径,确实存在于源代码中:
    grep -roE "getByTestId\('([^']+)'\)" generated/ | sed -E "s/.*'([^']+)'.*/\1/" | sort -u \
      | while read id; do grep -rq "$id" src/ || echo "MISSING testid: $id"; done
    
  3. 运行一次测试套件。 引用了不存在的路由 / 选择器的测试会立即失败;在审查前将这些测试隔离,而不要审查无效代码。

任何 MISSING 行或 tsc 错误都表示存在臆造内容,必须在人工投入审查时间前修复。

反模式

  1. 跳过步骤,直接写代码。 最常见的失败:Agent 拿到 PRD 后就立即编写测试。没有覆盖矩阵,就会漏掉一些场景,还会重复覆盖另一些场景。这套流程就是为避免这种情况而设立的。
  2. 断言实现,而非行为。 expect(component.state.isLoading).toBe(true) 会在任何重构时失效。应断言 expect(screen.getByRole('progressbar')).toBeVisible()——也就是用户能观察到的内容。
  3. 混淆场景和断言。 把“测试这件事并检查这个值”写成一个步骤。应将测试什么与如何验证分开。
  4. 提示词中没有项目上下文。 没有项目约定和现有模式,就只能得到通用测试。qa-project-context.md 正是为此而设。
  5. 生成过多。 AI 可能会为一个简单函数编写 50 个测试。每个测试都会增加维护成本。使用覆盖矩阵,将生成范围限定在有意义的场景内。
  6. 不求甚解地复制粘贴。 如果你无法解释生成的测试做了什么,以及为什么这么做,就不要合并。你不理解的测试,出了问题也无从调试。
  7. 未经审查就交付。 第 7 步不是可选项。AI 测试经常包含幻觉 API、错误的选择器、不正确的业务逻辑,以及只有人工审查才能发现的不稳定性。
  8. 忽略反馈闭环。 AI 测试发现真实 Bug 时,记录有效的提示词模式;出现误报时,记录问题所在。建立项目专属的有效方法库。

完成标准

  • 七项产物全部齐备:需求文档、风险与不变量、覆盖矩阵、场景集、判定标准定义、测试代码,以及包含每项测试 KEEP/MODIFY/REJECT/DEFER 决策的审查记录。
  • 在编写任何测试代码文件之前,已生成并审查覆盖矩阵。
  • 验证通过:tsc --noEmit(或对应语言的等效命令)以 0 退出,并且选择器/端点 grep 结果中没有 MISSING 行。
  • 每项生成的测试都有记录在案的人工审查决策;没有任何测试在缺少审查决策的情况下被标记为 KEEP。
  • 套件的 CI 作业以 0 退出(绿色)。
  • 已记录可复现性元数据:确切的模型 ID(例如 claude-opus-4-8、claude-sonnet-4-6、claude-haiku-4-5-20251001)、输入源哈希,以及所调用的任何 skill / CLI / MCP 服务的版本。

相关 Skills

  • qa-project-context — 设置上下文文件,大幅提升 AI 生成测试的质量。请先配置此项。
  • playwright-automation — 深入介绍 Playwright 模式(POM、fixtures、CI),以及 Test Agents(init-agents --loop=claude,脚手架生成到 .claude/agents/ 中)和在 Discovery Q2 中选择的 @playwright/mcp 模式。生成的测试会放在此框架内。
  • unit-testing — 用于生成单元级测试的 Jest、Vitest、pytest 模式。
  • api-testing — 从 OpenAPI 规范生成测试时使用的端点测试模式。
  • test-strategy — 在生成测试之前,决定测试什么以及在哪个层级测试。
  • test-reliability — 提高生成测试的可靠性:不稳定测试分类、修复、视频凭证。
  • ai-system-testing — 当输入是 LLM 功能规范时,在此处生成评估数据集(Promptfoo、DeepEval、Ragas、Braintrust),而不是生成 Playwright 规范。
  • ai-qa-review — 审查你并非刚刚生成的现有测试套件(测试异味、可测试性)。此处的第 7 步仅审查这套流程自身的产出。
  • ai-bug-triage — 生成的测试发现 Bug 时,通过分诊流程对其分类并报告。

参考文件(位于 references/ 中)

  • prompt-patterns.md — 与七个步骤对应的完整提示词库:提取、风险分析、场景生成、判定标准设计和代码生成提示词,以及第 4 步中使用的 BOUNDARIES 边缘情况框架。

评论

支持 Markdown