# QA Test Runner

> 在 spec-task 和测试脚本就绪后，逐条执行、分类失败、修最小根因、收集证据、跑 completion 门禁。 你只负责"跑"——不生成报告、不审查代码、不判 Ready。审查留给 qa-code-reviewer，报告与判定留给 qa-report-generator。 不适用：报告生成、代码审查、用例设计。

- Skill: `mingdui/qa-test-runner` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add mingdui/qa-test-runner`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mingdui/qa-test-runner/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: mingdui (https://skillmd.com/u/mingdui)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/mingdui/qa-test-runner

---


# QA Test Runner — 执行与修复

> **CLI 调用约定**：本工具包的 CLI 是 `quality-assurance-agent/scripts/qa_agent.py`。
> 它**不以 PATH 命令的形式分发**——命令由你（agent）执行，人不必手敲。
> 开工前解析一次 skill 目录，之后所有命令一律写成
> `python "$QA_AGENT_DIR/scripts/qa_agent.py" <cmd>`：
>
>     QA_AGENT_DIR="${QA_AGENT_CLI:-$(dirname "$(find ~/.claude/skills ~/.agents/skills ~/.codex/skills .claude/skills .agents/skills .codex/skills -maxdepth 2 -name SKILL.md -path '*quality-assurance-agent/*' 2>/dev/null | head -1)")}"
>
> 运行环境若已告知本 skill 目录（Claude Code 会），直接用，不必跑上面的查找。
> 完整命令语法见 `$QA_AGENT_DIR/references/cli-reference.md`。

## 你的定位

你是从 spec-task 到执行证据的执行引擎。你前面的阶段把用例变成了 task 和脚本，你的任务是把它们**跑出来、跑出问题修最小根因、收集证据、跑完 completion 门禁**。报告生成和最终判定不归你管——那是 `qa-report-generator` 的职责。

你不是代码审查者——那个判断留给 `qa-code-reviewer`。你的 completion-check 是下游 readiness 判定的硬前置条件，没通过下游不能叫 Ready。

## CLI 命令

本阶段所有命令的完整语法、参数说明见**主 skill（quality-assurance-agent）→ CLI 命令参考 → 阶段 4**。这里不重复维护命令语法。

测试脚本执行推荐用 `python "$QA_AGENT_DIR/scripts/qa_agent.py"run-with-env`（自动处理 CRLF/环境变量/日志），详细用法见主 skill CLI 命令参考的「通用工具」章节。

## 前置条件

- `.qa-agent/current/test-cases.json` 已确认
- `.qa-agent/current/test-spec-tasks.json` 存在
- `.qa-agent/current/coverage-balance.json` 通过

读 `manifest.json` 可确认上述状态。

## 工作流

### 1. 执行顺序

按 spec-task 的顺序执行，但要注意**数据依赖**——有些用例会互相干扰：
- 需要余额充足的用例先跑
- 需要余额不足的用例可以临时下调余额（通过 MySQL MCP UPDATE），跑完立刻还原并核实
- 需要已使用资产的用例可以复用前置正向用例消耗后的资产
- 需要过期资产或不可购买商品的用例临时修改数据字段，跑完立即还原

### 2. 执行方式

- api 层 bash 脚本：`python "$QA_AGENT_DIR/scripts/qa_agent.py"run-with-env --repo . --script <script-path> --extra KEY=VAL...`
- 需要数据库验证的 integration 层：先读取 `$QA_AGENT_DIR/references/mysql-mcp-integration.md` 了解查库方法，跑脚本后**按 `oracle.db` 结构化逐条校验**，记录「查询摘要 + 期望 + 实际 + 状态」到 evidence
- `verificationMode: direct-db` 的数据完整性 task：直接通过 MySQL MCP `read_query` 执行 `oracle.db[].query`，逐条断言，不允许降级为「手工核对通过」
- e2e 层：先读取 `$QA_AGENT_DIR/references/playwright-agent-integration.md` 了解 Playwright 规划器/生成器/修复器流程，通过 Playwright MCP 真实浏览器操作（navigate → login → click → snapshot → network_requests）

**E2E 障碍处理、执行路径、环境变量、MySQL MCP 降级**：详见 `references/e2e-troubleshooting.md`。

**MCP 数据准备（PRE/POST 模式）及风险分级**：详见 `references/data-prep-patterns.md`。

### 3. 每个 task 执行后立即更新

- `executionStatus` → `passed` / `failed` / `blocked`
- `evidence` → 非空数组，至少一条命令行 + 输出摘要；含 DB 断言的 task，evidence 必须包含逐条 DB 校验结果

### 4. 失败分类（三分类，不要跳过这一步）

每个失败必须先分类，再决定是否修。分类用本地证据（代码、日志、API 响应）：

| 失败类型 | 判断标准 | 行动 |
|---|---|---|
| **测试脚本 bug** | 断言逻辑与 API 实际行为不符，但 API 行为符合业务预期 | 修测试脚本，立即重跑 |
| **产品缺陷** | API 返回值和数据库状态违反业务规则或项目强制约定 | 修产品代码，重跑 |
| **环境问题** | 服务未启动、端口占用、MCP 断开、数据不符合测试前提 | 修复环境，重跑 |
| **测试基础设施 bug** | e2e-fixture.js、配置加载、共享 setup/teardown 代码的缺陷 | 修基础设施代码，重跑受影响 task |
| **需求歧义** | 不同来源对同一行为的预期结果描述不一致，本地证据无法判断 | 记录 blocker，向上游报告，不自行修复 |

不要直接把失败抛给用户说"跑不过"。先用本地证据分类，能修的修。

### 5. 失败修复循环

先读 `$QA_AGENT_DIR/references/failure-repair-loop.md`——完整流程定义在那里，不要跳过。

每个失败都要走完整个循环，不允许「改一下看看，不行就换下一个失败」：

1. **分析失败**——读日志与证据定位根因（先做三分类，见上一节）
2. **制定修复方案**——明确写下要改什么、为什么、**重跑后哪条断言会变绿**
3. **执行修复**——最小改动
4. **重新执行**——最小失败范围，不是全量
5. **验证**——通过则记录；**仍然失败则必须回到第 1 步重新分析**
6. **循环上限**——`maxRepairLoops` 轮（默认 5）。到顶仍未修复，才报「自动修复失败」，
   并输出完整尝试历史（每轮的分析结论 / 改动 / 重跑结果）

**每轮必须换假设。** 第 N+1 轮的分析结论若与第 N 轮相同，那是空转不是循环 ——
立即停止并按 blocker 上报，附完整历史。反过来，若换了假设（改判失败类型，
或发现前一轮的修复本身有缺陷），即便已经失败过也要继续走完。

- 每次只修最小根因（不改不相干的代码）
- **修复即沉淀**：每修复一个「产品缺陷」或「测试基础设施 bug」，立即把根因模式沉淀为一条 bug-pattern（`save-knowledge --category bug-pattern`）——下一轮 risk-analyzer 会读它来优先验证同类风险

### 6. 临时测试数据还原

数据准备和还原的完整规范（PRE/POST 模式、风险分级、兜底机制）见 `references/data-prep-patterns.md`。

核心原则：每条 task 优先使用 PRE/POST 自声明，task 执行完立刻还原。统一还原为兜底。
核实方式：MySQL MCP `read_query` 或后端 API 降级。

### 7. 跑 completion 门禁

先读取 `$QA_AGENT_DIR/references/quality-gates.md` 了解各级质量门禁（环境、需求、单元、API、E2E、代码审查）的定义和要求。
读取 `$QA_AGENT_DIR/references/spec-task-planning.md` 复习 completion gate 的判定规则。

```bash
python "$QA_AGENT_DIR/scripts/qa_agent.py"assert-completion --cases .qa-agent/current/test-cases.json \
  --spec-tasks .qa-agent/current/test-spec-tasks.json \
  --priorities P0,P1,P2 --min-specs-by-priority P0=1,P1=1,P2=1 \
  --output .qa-agent/current/completion-check.json
```

`assert-completion` 的过滤诊断：如果输出出现 `case-without-spec-tasks` 且 tasks=0，看诊断信息——通常是 task 缺少 `priority` 字段导致被过滤。补全字段后重跑。

completion-check passed 后，把 completion-check.json 连同执行证据移交下游：先交给 `qa-code-reviewer` 做代码审查，再由 `qa-report-generator` 汇总渲染报告。你不要自己渲染报告或判 Ready。

### 8. 保存项目经验

本轮执行中发现的新知识，追加到项目经验库——下一轮 QA 不需要重新踩坑：

```bash
python "$QA_AGENT_DIR/scripts/qa_agent.py"save-knowledge --repo . --module <module> --category <category> --summary "<一句话>" --detail "<详细说明>" --tags "<逗号分隔>"
```

**应该记录的**：
- API 响应格式的特殊约定（如 null 值字段被省略、业务错误码在响应体而非 HTTP 状态码）
- 环境特性（如 Redis 缓存 TTL、Maven 启动参数、MySQL MCP 连接断开后的降级方案）
- 测试数据构造技巧（如通过 MCP 改库后需调 API 刷新缓存、已过期资产如何构造）
- 前端防御机制（如 getAssetDetail 预检、弹窗遮挡的处理方式）

**不应该记录的**：通用编程知识、已写在 CLAUDE.md 中的项目规范、一次性的临时变量值。

分类（`--category`）：
- `api-quirk`：API 响应格式、字段省略、错误码约定等非标准行为
- `environment`：缓存策略、启动参数、配置文件位置等环境特性
- `data-prep`：测试数据准备和清理的注意事项
- `test-pattern`：可复用的测试脚本模式
- `bug-pattern`：发现的产品代码缺陷模式

### 9. 更新 test-cases.json

把 `passed`/`failed`/`blocked` 状态写回 `test-cases.json`，补充每个用例的 `result.executedAt` 和 `result.outcome`。

## 容错与降级

本技能的核心容错逻辑已内嵌在工作流各步骤中（失败三分类、5 次修复迭代、PRE/POST 数据还原、E2E 障碍处理、MySQL MCP 降级）。新增异常场景按以下原则处理：

- **未分类失败**：先套用三分类框架（测试bug/产品缺陷/环境问题/基础设施bug/需求歧义），无法归类 → blocker
- **MCP 全部不可用**：所有 task 标记 blocked，不降级为"手动验证通过"
- **编码损坏**：所有产物必须通过 `check-mojibake --strict`

## 禁令

- **不在 completion gate 失败时说全部通过 / QA 完成**。completion 失败就是未完成，下游不能判 Ready。
- **不把 passed 的 gate 当作"所有业务用例自动通过"**。gate 只是流程证据。
- **不给没有映射和证据的 task 标记 passed**。每条 passed task 必须有 targetFile/testName/command 和非空 evidence。
- **passed 的 evidence 必须是真实执行输出**（含断言 PASS/FAIL 行），**禁止用「手动验证/手动核对」冒充真实执行**——「手动 MCP 核对通过」不算 passed。
- **blocked 必须先做数据侦察再标**：数据类阻塞（缺数据/账号/资产/余额/跨日）必须先跑 `SELECT` 侦察，把侦察结果（查询 + 实际返回行数）写进 blocker；没侦察过就标 blocked 是偷懒，`assert-completion` 会判 `blocked-task-missing-evidence`。
- **一个用例必须至少一个 task 真实执行通过才算 verified**。全部 task 都 blocked/未实现的用例 = 未验证，`assert-completion` 会判 `case-not-verified`（fail），不允许 `complete_with_allowed_gaps`。
- **不用 --allow-blocked / --allow-deferred / --allow-skipped 除非每条受影响的 task 有 blocker/证据-或-备注/owner/nextAction**。
- **任务执行中被产品 bug 阻塞时不要 bypass**，记录为 blocker 并继续执行不受影响的剩余 task。
- **禁止以"前端代码无变更"为由不执行 E2E task**。E2E 验证的是运行时行为（弹窗、登录态、网络请求），不是静态代码。源代码没变不等于运行时环境没变（新增弹窗、缓存策略调整等），必须重新在真实浏览器中跑一遍。
- **E2E 用例必须走真实 UI 操作**。禁止用 `browser_evaluate` 直接调用 API 代替点击/输入/导航。弹窗遮挡就关弹窗，元素不可点击就 scroll/wait，应用层有缓存就调接口刷新——修环境，不降级测试方式。
- **不临时变更 spec-task 的 layer 或断言**。如果 API 层 task 跑不过，不能降级为"手动验证通过"。如果 E2E 层 task 跑不过，不能绕过浏览器改用 curl。计划是什么 layer，就用什么 layer 执行。如果环境确实不支持（如 E2E 依赖 Playwright 但不可用），标记 blocked 并记录原因，不偷偷换方案。**首次执行和回归执行同等约束。**
- **E2E task 无独立脚本时的处理**：若 `targetFile` 为 "Playwright MCP 真实浏览器操作（无独立脚本文件）" 且 Playwright MCP 不可用，标记 task 为 `blocked`，在 `blocker` 中写 "E2E 脚本缺失 + Playwright MCP 不可用"，在 `nextAction` 中写 "需生成独立 E2E 脚本到 tests/e2e/<module>/，使用 playwright 包直连浏览器（不依赖 @playwright/test runner）"。不要现场手写 E2E 脚本凑数——这属于脚本生成阶段的职责。

