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 的「归因三分类」和自愈机制,我们下篇见。

相关推荐
鱼日先生1 小时前
Dify 中级实验(04):迭代进阶——如何批量处理数据并守住性能边界?
agent·工作流·dify
circuitsosk2 小时前
不止于API调用:大模型推理加速与云原生服务化部署指南
python·云原生·agent·vllm·推理加速·大模型部署·ensorrt-llm
@Mr_LiuYang2 小时前
《深入理解 AI Agent:设计原理与工程实践 》实验1-2 深度搜索能力
人工智能·agent
苏灿烤鱼3 小时前
今日 GitHub 热门|Agent 记忆重回榜首,+2,690 项目却只排第三
typescript·agent·资讯
苏灿烤鱼3 小时前
GitHub #2 拆解|把工程经验装进 Agent,为什么仍会“静默失效”?
javascript·人工智能·agent
大模型momo12 小时前
告别单体 Agent:多智能体设计模式(Multi-Agent Patterns)深度实战手册
人工智能·agent·multi-agent·多agent
很楠爱上13 小时前
(附上相关学习资源)适合新手做的第一个agent项目*ovo*Dify Agent 全栈实战:从智能选车顾问到新能源汽车之家的端到端开发
人工智能·汽车·agent·项目·开发笔记
用户4693684832016 小时前
kimi-code 深度掌握系列文章-对话循环TurnFlow(五)
llm·agent
Loveyourself17 小时前
什么是cc中的session memory compact(background notes)?
agent