做过测试的都知道,写用例是整个流程里最耗体力的环节。一个中等复杂度的功能模块,手工写完 200 条用例,快的半天,慢的一天半。而且写完还不一定靠谱 —— 漏场景、漏边界值、漏异常路径,review 的时候才发现 "这个状态没测"。

AI 当然该干这个活。市面上也确实有工具号称能 "AI 生成测试用例",但用下来发现一个共同问题:写得像,但不靠谱。我想要的不是一个 "看起来像测试用例的文本生成器",而是一个可量化、可校验、覆盖率 100% 的测试用例生产线。

一、为什么做这个 Agent

1.1 痛点:测试用例是体力活

测试用例编写的痛点已经是行业共识:

  • 效率低:200 条用例人工编写需要 0.5-1.5 天
  • 质量不稳定:依赖测试人员经验,漏测率平均达 35%(来源:《2024 软件测试行业白皮书》)
  • 维护成本高:需求变更时,用例更新的工作量相当于重写 60%
  • 覆盖率难量化:大多靠 "我觉得测够了",没有客观衡量标准

市面上的 AI 生成工具普遍存在三个问题:输出不可控、格式不稳定、数字不可信。说白了,就是看起来像人写的,但实际不能直接用。

1.2 目标:可量化、可校验、100% 覆盖

我给这个 Agent 定了三个核心指标,缺一不可:

要求含义
可量化每条用例归属哪个维度、覆盖了哪个元素,一目了然
可校验覆盖率是代码算出来的,不是 AI 编出来的
100% 覆盖基于 ISO/IEC/IEEE 29119-4 的 9 维度模型,每个元素都有对应用例

这意味着不能用 "让 LLM 自由发挥" 的方式 —— 你得控制它、约束它,然后用代码验证它。

二、架构演进:三个版本的踩坑之路

2.1 版本一:纯 Bot Prompt

思路:把 ISO 29119 标准、覆盖方法论、用例编写规范全写进 Bot Prompt,让 LLM 一次搞定。

plaintext

┌─────────────────────────────────────────────┐
│              纯Bot Prompt 架构               │
│                                             │
│  用户需求 ──→ [LLM Bot] ──→ 测试用例+覆盖率  │
│               (全写进Prompt)                 │
└─────────────────────────────────────────────┘

听起来很美,实际跑起来三个致命问题:

问题具体表现
输出不可控同一需求跑三次,三次字段列表、用例数量、分类方式都不一样
格式不稳定有时 Markdown 表格、有时纯文本、有时中途截断(token 超限)
数字不可信LLM 告诉你 "覆盖率 85%",实际可能是 60% 也可能是 110%—— 它是编的

结论:LLM 是生成器,不是校验器。让它写用例可以,让它算覆盖率 —— 算了。

2.2 版本二:Bot + 工作流

既然 LLM 不可信,就把 "可信" 的部分交给代码。思路:LLM 只负责生成,代码做校验。5 节点工作流:

plaintext

┌──────────────────────────────────────────────────────────────┐
│                    版本二:5节点工作流架构                      │
│                                                              │
│  用户需求                                                     │
│     ↓                                                        │
│  [Node1] LLM需求结构化提取                                     │
│     ↓ JSON                                                   │
│  [Node2] 代码隐含补全 (46ms)                                   │
│     ↓                                                        │
│  [Node3] 代码覆盖元素推导 (20ms)                                │
│     ↓                                                        │
│  [Node4a] LLM主用例生成 ──┐                                    │
│  [Node4b] LLM补全用例生成 ──┤── 并行                            │
│     ↓                                                       │
│  [Node5] 代码校验+合并+统计 (10ms)                              │
│     ↓                                                        │
│  12个变量输出 → Bot展示                                        │
└──────────────────────────────────────────────────────────────┘

解决了 V1 大部分问题:覆盖率代码算、格式代码控、数字代码统计。但新问题来了 —— 数据一致性崩了:

plaintext

┌─────────────────────────────────────────────────┐
│           版本二的数据流问题                       │
│                                                 │
│  Node5输出 ──→ 12个变量 ──→ Bot读取展示          │
│                    ↑          ↑                  │
│                    │          │                  │
│               当次有效    后续轮拿不到!           │
│                          Bot自己编数据           │
│                                                 │
│  结果:引导语说75%,详情页说68% → 信任归零         │
└─────────────────────────────────────────────────┘
问题原因
变量后续轮不可访问Coze 工作流变量只在当次调用有效
Bot 自行编造数据拿不到变量,LLM 就 "推理" 一套数据出来
引导语和详情页数字打架两个数据源:Node5 算一套,Bot 编一套

结论:生成质量 OK 了,但数据一致性崩了。用户看到两个不一样的数字,信任归零。

2.3 版本三:Bot + 工作流 + 用户变量

数据一致性崩的根因是两个数据源。根治必须统一到一个数据源。思路:用户变量持久化,workflow 结果写入变量,Bot 只从变量读,严禁自造。

plaintext

┌──────────────────────────────────────────────────────────────────┐
│                版本三:单变量持久化架构(最终版)                     │
│                                                                  │
│  用户需求                                                         │
│     ↓                                                            │
│  [Node1] LLM需求结构化提取                                         │
│     ↓ JSON                                                       │
│  [Node2] 代码隐含补全 (46ms)                                       │
│     ↓                                                            │
│  [Node3] 代码覆盖元素推导 (20ms)                                    │
│     ↓                                                            │
│  [Node4a] LLM主用例生成 ──┐                                        │
│  [Node4b] LLM补全用例生成 ──┤── 并行                                │
│     ↓                                                           │
│  [Node5] 代码校验+合并+统计 (10ms)                                  │
│     ↓                                                            │
│  ┌─────────────────────────────────┐                              │
│  │  all_data (单变量, 用户变量持久化) │                              │
│  │                                 │                              │
│  │  @@@COVERAGE@@@  覆盖率报告      │                              │
│  │  @@@D1@@@        输入字段详情     │                              │
│  │  @@@D2@@@        业务规则详情     │                              │
│  │  ...                            │                              │
│  │  @@@D9@@@        非功能详情      │                              │
│  │  @@@GROUP1@@@    [1]功能+接口    │                              │
│  │  @@@GROUP2@@@    [2]异常+安全+性能│                              │
│  └─────────────────────────────────┘                              │
│     ↑ 写入                    ↓ 读取                              │
│  Node5代码                  Bot零计算只抄                          │
│                                                                  │
│  ┌──────────────────────────────┐                                │
│  │       三层质量保障             │                                │
│  │                              │                                │
│  │  ① LLM生成 → 结构化提取+用例  │                                │
│  │  ② 代码校验 → 覆盖率+统计     │                                │
│  │  ③ 人工校验 → 未覆盖元素导航   │                                │
│  └──────────────────────────────┘                                │
└──────────────────────────────────────────────────────────────────┘

踩了最隐蔽的坑 —— 变量写入静默截断,后面详细讲。最终验证通过:登录、注册、支付三个场景,覆盖率报告和详情页数字 100% 一致。

三、8 个关键问题与解决过程

#问题严重度根因
1LLM 输出截断与超时🔴高单节点输出量 / 执行时间超限
2列索引偏移 cols [6]→cols [7]🔴高Markdown 表格 split 后空列偏移
3Bot 自行编造数据🔴高Prompt 未禁止 + 变量不可用
4数据不一致(双数据源打架)🔴高架构层面双数据源
5工作流变量后续轮不可访问🔴高Coze 平台限制
6用户变量写入静默截断🔴极高reply_length 影响赋值上限,isSuccess 仍返 true
7变量修改时间误导排查方向🟡中平台元信息与业务操作无关
8变量赋值 {{}} 模板字符串污染🔴高部分变量未输出导致残留

问题 1:LLM 输出截断与超时

现象:Node1 偶发 117 分钟超时(正常 55 秒);Bot 端渲染 5-8 分钟,同会话第二轮 12 分钟 +。定位过程:怀疑 all_data 太大 → 验证:第一轮 all_data 已灌入,为何第二轮更慢?↓真正的膨胀源:Bot 每轮强制携带完整对话历史↓第一轮输出的覆盖率报告 + D 维度表格全留在上下文里第二轮要读全部历史 → token 逐轮膨胀 → 渲染逐轮变慢

解决方案

措施效果
上下文轮数 3→1Bot 不依赖历史,切断膨胀链
Temperature=0减少采样开销
开场白设预期用户心理预期管理
引导开新话题避免同会话累积

💡 经验:LLM Agent 的性能瓶颈往往不在 LLM 本身,而在平台的上下文管理机制。先搞清楚瓶颈在哪,再决定优化方向。

问题 2:列索引偏移 ——cols [6]→cols [7]

现象:Node5 解析 Node4 输出的 Markdown 表格时,列索引错位。定位过程

python

# 预期:cols[6] 取第7列
# 实际:split后多了空字符串,索引全偏移+1

# 原始行
"| TC-001 | 提交订单 | 正常 | 成功 | 200 | OK | 无 |"
# split("|") 后
['', ' TC-001 ', ' 提交订单 ', ' 正常 ', ' 成功 ', ' 200 ', ' OK ', ' 无 ', '']
#  ↑ 空串!导致所有索引偏移

根因:行首行尾的 | 在 split 后产生空字符串;单元格内容含 | 也会产生额外列。

解决方案

python

# 修复:split前strip + 过滤空串
cols = [c.strip() for c in line.strip('|').split('|') if c.strip()]

💡 经验:Markdown 表格解析是字符串处理的经典陷阱,永远不要假设 split 后的索引是稳定的。

问题 3:Bot 自行编造数据

现象:用户查询 D1 维度详情,Bot 输出了完整的元素列表和覆盖率数字,但和 workflow 实际结果完全不一致。定位过程:Bot 拿不到 workflow 变量数据(平台限制:变量只当次有效)↓Bot 用 LLM 的 "推理能力" 编了一套看起来合理的数据↓数字看起来对,实际是编的 → 信任崩塌

解决方案:Bot Prompt 铁律(加粗 + 反复强调):

⚠️ 严禁自行编造任何数据⚠️ 所有数据必须从用户变量读取⚠️ 如果变量为空或读取失败,输出异常提示,不得用 LLM 生成的内容替代

💡 经验:LLM 的 "推理能力" 在数据展示场景是 bug 不是 feature。你希望它说 "我拿不到",而不是编一套看起来很对的数据。

问题 4:数据不一致 —— 两个数据源打架

现象:引导语显示 "D1 覆盖率 75%",点进 D1 详情页变成 68%。同一份报告,两个数字。定位过程:引导语数据 ← Node5 代码计算,写入变量详情页数据 ← Bot 从历史对话 "回忆" 并重新格式化↓两个数据源 → 两套计算逻辑 → 两套数字 → 打架

解决方案:统一为单一数据源。

plaintext

Before(双数据源):
  Node5计算 → 变量 → Bot展示(引导语)
                    → Bot回忆 → 重新展示(详情页)  ← 第二个数据源!

After(单一数据源):
  Node5计算 → all_data(用户变量) → Bot只抄,零计算零推理
  所有数字由Node5代码算,Bot从all_data对应@@@段原样读取

💡 经验:数据一致性不是 "写对了就行" 的问题,是架构问题。只要存在两个数据源,早晚打架。从一开始就设计成单一数据源。

问题 5:工作流变量后续轮不可访问

现象:用户第一次输入需求,workflow 正常,结果展示正常。同一对话里输入 "查看 D1",Bot 拿不到上一次 workflow 的输出。定位过程:Coze 工作流变量只在当次调用生命周期内有效,这是平台限制。

解决方案

plaintext

Before:工作流变量(当次有效)
  用户输入需求 → workflow运行 → 变量有值 → 展示OK
  用户查询D1   → 无workflow调用 → 变量为空 → Bot编数据

After:用户变量(持久化)
  用户输入需求 → workflow运行 → all_data写入用户变量 → 展示OK
  用户查询D1   → 不调workflow → 从用户变量读取all_data → Bot只抄对应段

💡 经验:平台限制不是你能改的,但架构可以绕。关键是在设计之初就想清楚数据生命周期。

问题 6:用户变量写入静默截断 —— 最隐蔽的坑 🔴

现象:变量赋值节点返回 isSuccess: true,变量修改时间也更新了,但实际数据被截断 ——all_data 前半段正常,后半段为空。定位过程:以为是 Node5 代码 bug → 本地运行输出完整 → 排除↓怀疑变量大小限制 → Coze 文档没提上限↓最终定位:Bot 的 reply_length 参数影响变量赋值写入上限默认值 ≈ 12000 字符,而 all_data 经常超过 30KB↓最坑的:截断后 isSuccess 仍返回 true!变量修改时间也正常更新!你完全不知道数据丢了!

解决方案

措施说明
Bot reply_length 调至 50000确保 30KB + 的 all_data 完整写入
数据完整性校验写入后检查 all_data 是否包含所有 @@@标记
铁律isSuccess 和修改时间都不可靠,只信业务数据本身

数据丢失检测逻辑(Node5 代码末尾):

javascript

if (!all_data.includes("@@@GROUP2@@@")) {
    return "⚠️ 数据加载异常,请重新输入需求描述";
}

💡 经验:静默失败比显式失败可怕 100 倍。 显式失败你马上知道有问题,静默失败你可能永远不知道数据丢了。任何涉及持久化写入的操作,都必须有独立的完整性校验机制。

问题 7:变量修改时间误导排查方向

现象:查看变量修改时间,时间更新了,确信数据已写入。但实际内容是旧的 —— 变量没被更新,修改时间却被平台刷新了。定位过程:平台变量的元信息更新和数据写入是异步的,某些内部操作会刷新元信息但不改变业务数据。

解决方案:完全不依赖修改时间做判断,用数据内容本身做校验(如检查 all_data 是否包含预期的 @@@标记)。

💡 经验:平台提供的元信息(修改时间、成功标识)是运维层面的,不是业务层面的。业务正确性必须用业务手段验证。

问题 8:变量赋值 {{}} 模板字符串污染

现象:Bot 输出中出现原始的 {{d1_out}} 未解析变量名,或数字位置出现 NaN。定位过程:12 个独立变量 → Bot Prompt 用 {{d1_out}} 等占位↓某个变量 Node5 未输出 → Coze 不解析 → {{d1_out}} 原样留在文本中↓更严重:Bot Prompt 写 {{xxx}} 示例 → Coze 当成变量语法报非法变量错误

解决方案

plaintext

Before(12变量):
  d1_out, d2_out, ..., d9_out, group1_out, group2_out
  → 12条映射,12个可能失败的点
  → 部分缺失 → {{}}残留 → 污染输出

After(1变量):
  all_data(单变量,@@@标记分段)
  → 1条映射,0个残留可能
  → Bot按@@@标记读取对应段落,不需要变量名引用

💡 经验:变量越多,出问题的概率越高。N 个变量意味着 N 个可能失败的映射。合并为 1 个变量看似粗暴,但在当前场景下是最稳健的方案。

四、最终架构与验证结果

4.1 最终架构总览

plaintext

┌─────────────────────────────────────────────────────────────────────┐
│                      最终架构:5节点工作流 + 单变量持久化              │
│                                                                     │
│  用户输入需求                                                        │
│      ↓                                                              │
│  ┌──────────────────────────────────────────────────┐               │
│  │ [Node1] LLM需求结构化提取(豆包·2.0·mini, ~55s)   │               │
│  │   输入:用户需求文本                                │               │
│  │   输出:9维度结构化JSON                             │               │
│  └──────────────────────────────────────────────────┘               │
│      ↓ JSON                                                         │
│  ┌──────────────────────────────────────────────────┐               │
│  │ [Node2] 代码隐含补全 (46ms)                        │               │
│  └──────────────────────────────────────────────────┘               │
│      ↓                                                              │
│  ┌──────────────────────────────────────────────────┐               │
│  │ [Node3] 代码覆盖元素推导 (20ms)                     │               │
│  │   基于JSON推导9维度覆盖元素清单                      │               │
│  └──────────────────────────────────────────────────┘               │
│      ↓                                                              │
│  ┌──────────────────────┐  ┌──────────────────────┐                │
│  │ [Node4a] LLM主用例生成│  │ [Node4b] LLM补全用例  │  ← 并行       │
│  │ (DeepSeek-V3.2,1.24m)│  │ (DeepSeek-V3.2,1.34m)│                │
│  └──────────────────────┘  └──────────────────────┘                │
│      ↓                         ↓                                    │
│  ┌──────────────────────────────────────────────────┐               │
│  │ [Node5] 代码校验+合并+统计 (10ms)                   │               │
│  │   ① 逐条校验用例是否覆盖对应元素                     │               │
│  │   ② 计算各维度覆盖率                                │               │
│  │   ③ 生成覆盖率报告+维度详情+分组用例                  │               │
│  │   ④ 拼装all_data写入用户变量                         │               │
│  └──────────────────────────────────────────────────┘               │
│      ↓                                                              │
│  ┌──────────────────────────────────────────────────┐               │
│  │           all_data(用户变量持久化)                  │               │
│  │                                                    │               │
│  │  @@@COVERAGE@@@  综合覆盖率+各维度覆盖率+未覆盖元素  │               │
│  │  @@@D1@@@~@@@D9@@@  9个维度的覆盖元素详情            │               │
│  │  @@@GROUP1@@@  [1]功能测试+接口测试用例              │               │
│  │  @@@GROUP2@@@  [2]异常+安全+性能测试用例             │               │
│  └──────────────────────────────────────────────────┘               │
│      ↓                                                              │
│  ┌──────────────────────────────────────────────────┐               │
│  │  Bot(豆包·2.0·lite)                              │               │
│  │  - 零计算零推理,只从all_data抄对应@@@段              │               │
│  │  - 首轮输出覆盖率报告(@@@COVERAGE@@@)              │               │
│  │  - 用户查D1→输出@@@D1@@@段                          │               │
│  │  - 用户查1→输出@@@GROUP1@@@段                       │               │
│  └──────────────────────────────────────────────────┘               │
└─────────────────────────────────────────────────────────────────────┘

4.2 9 维度覆盖模型

维度提取数据来源用例类型归属分组
D1 输入字段覆盖fields功能测试[1]
D2 业务规则覆盖rules功能测试[1]
D3 状态转换覆盖states功能测试[1]
D4 异常场景覆盖key_operations异常测试[2]
D5 安全缺陷模式覆盖security安全测试[2]
D6 输出覆盖apis.response_fields功能测试[1]
D7 接口交互覆盖apis.error_codes接口测试[1]
D8 组合覆盖fields×rules 交叉功能测试[1]
D9 非功能覆盖key_scenarios性能测试[2]

4.3 用例类型 5 分类

用例类型归属分组说明
功能测试[1]覆盖 D1/D2/D3/D6/D8
接口测试[1]覆盖 D7
异常测试[2]覆盖 D4
安全测试[2]覆盖 D5
性能测试[2]覆盖 D9

4.4 四道质量关卡

plaintext

┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│ ① LLM生成 │───→│ ② 兜底补充 │───→│ ③ 代码校验 │───→│ ④ 人工校验 │
│           │    │           │    │           │    │           │
│ Node1提取  │    │ Node4b对   │    │ Node5逐条  │    │ 覆盖率报告  │
│ Node4生成  │    │ 未覆盖元素  │    │ 校验覆盖率  │    │ 标注未覆盖  │
│ 9维度结构  │    │ 补充生成   │    │ 计算真实值  │    │ 引导人工补  │
└──────────┘    └──────────┘    └──────────┘    └──────────┘

4.5 后续规划

版本方向说明
v6.1链接读取插件支持在线文档链接输入
v6.2性能深度优化按需注入、流式输出
v6.3按需生成 4 场景模式从 "全量生成" 进化到 "按需生成"
长期垂直行业扩展金融、医疗、电商等定制化规则

五、写给同路人

5.1 AI Agent 能为测试做什么

#能力说明
1需求结构化提取把自然语言需求拆成 9 维度结构 —— 后续一切的基础
2覆盖元素推导基于 ISO 29119 标准,自动推导每个维度该测什么
3批量用例生成200 + 条结构化用例,3 分钟出结果,替代 1 天手工
4覆盖率量化每个维度覆盖率多少、哪些元素没覆盖 —— 数字说话
5人工校验导航标注未覆盖元素,引导人工补充 —— 人机协同

5.2 适合谁用

・测试工程师:日常写用例太耗时间,想要靠谱的辅助工具

・测试管理者:需要量化团队测试覆盖情况,不想依赖 "我觉得测够了"

・创业者 / 独立开发者:一个人搞定测试,AI 就是你的测试搭档

六、反思与建议

给 Agent 开发者 3 条建议

1️⃣ LLM 是生成器,不是校验器

不要让 LLM 做它不擅长的事。生成内容是强项,校验、统计、格式化 —— 交给代码。你不会让一个诗人去当会计,同理。

2️⃣ 适配平台,而不是对抗平台

每个 Agent 平台都有自己的限制(变量生命周期、赋值上限、上下文管理)。不要试图绕过这些限制,而是把架构适配到平台的能力边界内:・变量不可跨轮 → 用用户变量持久化・赋值可能截断 → 加完整性校验・上下文会膨胀 → 控制轮数

3️⃣ 警惕静默失败

这是最危险的一类 bug。isSuccess: true 不代表真的成功了,修改时间更新不代表数据真的写了。任何涉及持久化写入的操作,都必须有独立的、基于业务数据的完整性校验机制。 否则你可能在错误的基础上越走越远。

给测试行业 1 个思考

AI 不是来替代测试工程师的,它是来改变测试工作重心的。

  • Before:80% 时间写用例 + 20% 时间思考和设计
  • After :20% 时间审核 AI 生成 + 80% 时间思考和设计

覆盖率报告告诉你 "哪些没覆盖",人工校验决定 "哪些该补充"。AI 是执行者,人是决策者。 这才是人机协同的正确姿势。不是 AI 替代你,是会用 AI 的人替代不会用的人。

试用与合作

  1. 👉 TestPilot 测试用例生成智能体立即试用
  2. 💼 全套 Prompt、工作流代码可商业授权,也欢迎技术交流 —— 私信或评论区留言均可

觉得有用的话,点赞收藏,评论区告诉我你的测试场景,我来看看 Agent 能不能帮到你。遇到问题也欢迎吐槽,这个 Agent 还在持续迭代,你的反馈就是下一个版本的方向。

📢 今日话题:你们团队在 AI 测试用例生成方面遇到过什么坑?欢迎在评论区留言!

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐