AI 自动化测试流水线实战(二):Analyst 把 PRD 变 L0/L1 用例套件

系列第二篇。上一篇讲了流水线的整体编排:5 个子 Agent + 看板驱动。这篇深入第一个真正"干活"的角色------Analyst,看它怎么把一份需求文档,变成一份结构化、可追溯、可确认的测试用例套件。


这篇解决什么问题

大多数 AI 生成用例的方案是:丢给 LLM 一句「帮我写 20 条测试用例」,然后它吐一堆 markdown 给你。问题来了:

  • 无法追溯:这条用例覆盖了需求里的哪一条?说不清。
  • 不可确认:生成一大堆,用户没法快速扫一遍确认"覆盖对不对"。
  • 尺度失控:说好 core,结果写出来一堆边界;说好全量,结果 happy path 都没写全。
  • 无法复用:这次生成的用例,下次换工具/换流程就废了。

Analyst 的目标,就是把「需求文档」加工成一份 带分层、带追溯、带覆盖索引、带确认闸门 的用例套件。


核心分层:L0 / L1 / L2(这是全文重点)

整套用例设计基于一个「分层」思想,产物真相只有一个,其他都是派生。

路径 角色 谁产生 能否手改
L0 cases/requirements.json 需求原子,溯源用 Analyst 解析 ---
L1 cases/suite.json 用例真相,用户确认闸门 Analyst 设计 确认前可改
L1 旁路 cases/coverage.json L0×L1 覆盖索引 脚本算出来 ❌ 禁止手改
L1 视图 cases/suite.md 只读渲染给人扫一眼 脚本渲染
L2 specs/*.mdcases/cases-ai.json 通道派生,确认后生成 脚本/主流程 可丢重生

一句话总结铁律:用例真相在 L1(suite.json);L2 的一切都是确认后的派生产物,丢了可以重新生成。

为什么要分这么细?因为不同产物生命周期完全不同:

  • L0 是溯源------需求变了,能算出哪些用例受污染。
  • L1 是对齐------人是靠这份确认用例方向的。
  • L2 是生产------转成 Playwright spec、扁平 JSON,跑完就完,坏了重生。

Analyst 怎么干活:四步流水

Analyst 是一个标准的子 Agent,它的执行流程是固定的(见 agents/analyst.md):

markdown 复制代码
1. 解析 task 参数(outputDir / reqSource / scope / goal)
2. 加载 skill(test-cases)        // 用例生成规范
3. parse:node helpers/parse-md.js <req.md> → cases/requirements.json   // 需求→L0原子
4. 基于 L0 + scope + goal 设计用例,写入 cases/suite.json              // →L1
5. coverage:node helpers/coverage.js req.json suite.json → coverage.json
6. 渲染只读视图:node helpers/render-suite-md.js suite.json → suite.md
7. 返回 JSON(含统计与覆盖摘要)

它有明确的红线规则,我最喜欢两条:

  • A1. 不编造未写明的 UI:需求没给的按钮文案/路由/接口,用语义占位符(如「登录按钮」),并标注「待页面校验」。禁止假装探索过页面。→ 这防止了"编需求"。
  • A3. 场景原子化:一条 case 只验证一条可判定路径,正向/反向/边界拆开。→ 这防止了"大杂烩用例"。

还有一个硬约束:A6. 无论成功失败,最后输出必须是 JSON,不能有别的文本。跟前一篇说的"强制 JSON 返回"一脉相承。

2. 一条用例长什么样

suite.json 里每条用例是高度结构化的,而非一句自由文本:

json 复制代码
{
  "id": "S-003",
  "title": "登录成功-正确凭证",
  "priority": "P0",
  "phase": "readonly",
  "design": {
    "phase": "readonly",
    "automation": "ui"
  },
  "trace": {
    "reqIds": ["R-001", "R-002"],
    "origin": "literal"          // literal=直译 / derived=边界反推 / exploratory=页面补洞
  },
  "steps": [
    { "action": "goto", "target": "/login", "value": "" },
    { "action": "fill", "target": "邮箱", "value": "test@example.com" },
    { "action": "fill", "target": "密码", "value": "Test@123456" },
    { "action": "click", "target": "登录", "value": "" }
  ],
  "expects": [
    { "type": "url", "value": "包含 /dashboard" },
    { "type": "element", "value": "设备总览标题可见" }
  ]
}

几个关键字段:

  • trace.reqIds :这条用例追溯到哪些需求原子(L0)。必须非空------用例不能是"无源之水"。
  • trace.origin:标注用例来源------直译需求 / 边界反推 / 页面补洞。审查时一眼看出哪些是需求的直接映射,哪些是 AI 发挥。
  • expects[].typeurl | text | element | api | data | custom。禁止空 expects,禁止「看起来正常」这种无法断言的预期。

3. 覆盖索引:L0×L1 交叉算覆盖率

Analyst 不算手动脉搏率,它调脚本算。coverage.js 做 L0×L1 的笛卡尔覆盖计算,产出 coverage.json。返回的 summary 会给主线程:

json 复制代码
{
  "summary": {
    "reqTotal": 12,        // 需求原子总数
    "casesTotal": 18,      // 用例总数
    "p0": 5,               // P0 用例数
    "coveredReqs": 10,     // 被用例覆盖的需求数
    "uncoveredReqs": 2,    // 漏掉的需求数 ← 审查重点
    "orphanCases": 0       // 无需求来源的孤儿用例
  }
}

uncoveredReqs: 2 这种数字极其重要------它告诉用户"有两条需求没被覆盖"。orphanCases: 0 防止 AI 写一堆不溯源的空用例。这两个数字是覆盖是否完整的第一道体检指标。

4. 确认闸门(这篇最核心)

Analyst 产出的 suite.json 默认是 meta.status: "draft"在用户确认之前,禁止派生任何 L2 产物 (红线:不能在确认前调用 to-specs / project-flat)。

主线程会向用户展示覆盖摘要,等用户说「确认」。确认后才执行:

bash 复制代码
# 1. 标记确认
node helpers/confirm-suite.js cases/suite.json

# 2. 派生平坦用例(给用例源用)
node helpers/project-flat.js cases/suite.json cases/cases-ai.json

# 3. 派生 Playwright 计划
node helpers/to-specs.js cases/suite.json specs/

这套设计有个非常专业的细节:陈旧检测 。如果需求文件的 SHA256 变了(meta.reqSourceHash 不一致),套件会被标为 stale,禁止静默覆盖已确认的用例------要先 diff 再重新生成。防止"需求改了,旧用例还在用"的隐性污染。


范围裁剪:scope 决定尺度

Analyst 不是每次都写满用例,而是按 scope 裁剪尺度:

scope 覆盖策略
smoke 每模块最多 1--2 条 happy path
core 关键旅程 + 主要异常
full core + 边界 / 权限 / 并发等

这是贴近真实测试管理的做法------冒烟、核心回归、全量回归本就是三种不同尺度的测试活动,不允许用一套尺度糊弄。


抄走什么

这篇的可复用设计:

  1. 分层产物 + 唯一真相源:L0 溯源 / L1 确认闸门 / L2 派生,别把所有东西压在一个文件里。
  2. 用例必须可追溯trace.reqIds 必须非空,审查能算出 uncoveredReqsorphanCases
  3. 不可确认就得卡住:draft 状态在用户确认前禁止派生下游产物;需求变了要标 stale 再 diff,不静默覆盖。

下一篇:用例生成后,测试跑挂了。怎么判断是定位器失效、真 Bug、还是环境问题?Healer 的「归因三分类」和自愈机制,我们下篇见。

相关推荐
冬奇Lab1 小时前
Code Agent 解剖(12):Harness 设计之二——上下文工程
人工智能·开源·agent
阿里云云原生3 小时前
智能体构建与进化——Agent 开源开发者沙龙·上海站精彩回顾 & PPT 下载
agent
樊小肆4 小时前
DeepSeeker-Code源码导读11-统一注册表registry
人工智能·agent
AI探索派4 小时前
Agent Teams和Agent Swarm是什么?多Agent协作原理实战拆解
人工智能·架构·agent
后端小肥肠4 小时前
开营 10 天变现率 20%:我用一套 Skill,把小红书虚拟资料跑成了可复制流程
人工智能·aigc·agent
莪_幻尘5 小时前
手把手书写你的第一个 AI Agent:当 Skill 有了记忆、角色和主动性
前端·agent
plainGeekDev5 小时前
Agent Prompt 怎么写:三个真实案例讲透
agent·ai编程·claude
不是株5 小时前
Agent Memory 架构
人工智能·agent
@atweiwei5 小时前
用 Rust 构建 Agent 应用的高性能框架:langchainrust 架构全景
人工智能·架构·rust·langchain·llm·agent·ai编程
武子康6 小时前
看不见的 Reasoning State,为什么不能拥有看得见的工具权限
人工智能·llm·agent