AI 驱动测试:当开发用 AI 提速,测试如何用 AI 跟上
一个测试工程师的”至暗时刻”
团队接到一个目标:开发一款功能复杂的企业级 AI 产品,两个月发布。开发那边很兴奋——Vibe Coding 加持,Claude、Cursor 轮番上阵,代码产出速度翻了几倍。团队人数扩张,每天主干上合入的 PR 数从个位数飙到两位数。功能像下饺子一样往里扔:知识库、智能体、工作流编排、笔记本工作室、RAG 问答、权限体系……
站在测试的位置看这一切,心情复杂。传统做法是什么?读 PRD,写用例,评审,执行,提 Bug,回归。一个完整周期少说三到五天。但现在,开发三天就把一个模块重构了,你的用例还在评审会上讨论措辞。更扎心的是:不是你不够快,而是这个游戏的规则变了。当开发的生产力被 AI 放大了好几倍,测试如果还在用人力线性堆叠,结局只有一个——要么人数同步翻倍(老板不答应),要么质量兜不住(用户不答应)。
我们选了第三条路:自己也用 AI。不是那种”让 ChatGPT 帮我写几条用例”的浅尝辄止,而是把 AI 作为测试工程师的协作搭档,搭建一条人机协同的测试生产线。
全景:一条主线、一层延伸
我们搭了三层架构,每层解决不同粒度的问题:
第一层:diff-analysis—— 解决”测什么”。功能持续集成,每次拉取代码后就自动分析变更,告诉你哪些功能受影响、补了哪些用例。
第二层:Story→脚本流水线—— 解决”怎么测”。把测试场景翻译成可执行的 API/UI 脚本,CI/CD 里每天跑,不需要人去点。
第三层:非功能测试—— 解决”扛不扛得住”。它不另起炉灶,而是把第二层沉淀的业务流程延伸到性能场景:日常化地验证少量并发、数据量增长、突发流量,而不是等到 HA 环境才做一次。
这三层不是瀑布式的——它们同时运转、互相补位。按增量分析输出回归范围、自动化脚本在 CI/CD 里跑、非功能测试日常化捕捉性能问题。第三层非功能测试的脚本,正是站在第二层沉淀好的业务流程之上做的改造——少了第二层,第三层会很难下手。
越是”决定测什么”、“判断够不够”、“在模糊地带拍板”的场景,越需要人来定边界。这一点我们会在每一层具体展开。
第一层:代码变了,用例跟着变
痛点
产品有 20 个功能模块,一千多条测试用例。开发团队每天合入大量代码,测试工程师不可能逐行去看。过去的做法是测试和开发沟通”这个版本改了什么”,但聊出来的颗粒度往往不够细。
我们需要一双”眼睛”,直接盯着代码库,每次有变更就能知道:这次到底改了什么、哪些已有用例受影响、哪些功能值得补新用例、哪些只是噪音可以直接忽略。一轮合并往往不是一处改动,而是夹着好几个模块、十几个提交,光靠人手工拆分边界很难跟上。
实现
我们搭了一套叫diff-analysis的系统,挂在被测应用的代码仓库上。平时可以直接运行,它会从上次分析的位置接着跑到最新提交;只有第一次接入时,才需要手动指定一个起始日期来建立基线。每次 git pull 之后,由 Git 的 post-merge 钩子自动触发,测试工程师不用盯着命令行。
AI 做的事情:
- 先切出这一轮的改动:把上次分析点到最新代码之间的增量单独拆出来,结合源码上下文、模块路径映射表,再对照现有的功能地图,判断这一轮到底动了哪些功能点。
- 给每个改动分流:同样是一处改动,AI 要判断它该写成新用例、只更新已有用例、归为后端提醒、还是直接拒绝。只有证据完整、确实有用户可见入口的改动,才会真正生成新用例建议;证据不足的,会被标注清楚原因后搁置或拒绝,而不是硬写。
- 最后落盘:生成的结果先做一遍结构化校验、按用例名去重,再累加写回测试用例表格,并把新增的功能点同步回各模块的功能地图,同时刷新那份汇总所有模块的 Excel 测试用例总表。
这些事情如果让人来做,一个十来人的团队面对一轮夹着十几个提交的合并,光把边界理清楚通常就要几天,还不一定理得干净。AI 跑完这一轮,真正省下的不是”写几条用例”的时间,而是”先把改动切片、再判断哪些值得写”的时间。
AI 做不了的几件事:
这一层 大部分规则还是要测试工程师先定下来:
- 模块代码路径映射表:基于业务判断,给系统划分功能模块、维护文件路径到模块的对应关系。
- 现有功能地图基线:每个模块都有一份功能地图(testcase/<模块名>_feature_map.md),它是这次增量分析的参照物。AI 只能在这份基线之上标注”这次改了哪些”,不能把增量当成另一份全量地图去重写。
-** “什么构成功能变更”的定义**:总结”不构成功能变更”的代码改动模式——import 调整、注释修改、typo 修复、纯重构、类型扩展……这张”负面清单”是防止 AI 对噪音做反应的关键。
- 生成决策:同样是变更,有的是新用例,有的是只更新已有用例,有的是后端提醒,有的是直接拒绝。这个分流不是 AI 自己拍脑袋,得靠工程师先把门槛定死。
- 用例审核:AI 建议的每一条用例,最终都要工程师过一遍。不只是看”对不对”,还要判断”值不值得纳入正式用例集”。有些东西技术上可以测,但业务上没意义——这种取舍只有人能做。
实操示例
这套系统挂在被测应用的 Git 仓库里,git pull 后通过 post-merge hook 自动触发,工程师无需手动介入:
# 安装一次即可(把 hook 复制到被测应用 .git/hooks/)
cp automation-test/diff-analysis/hooks/post-merge project-ai/.git/hooks/post-merge
chmod +x project-ai/.git/hooks/post-merge
# 首次接入时显式建立基线
cd project-ai
./diff-analysis/scripts/run-analysis.sh --from-date 2026-05-01
# 之后日常无参续跑
./diff-analysis/scripts/run-analysis.sh
比触发方式更关键的,是约束 AI 产出质量的那套铁律。下面是 module-analysis.md 中的核心约束(节选):
## 铁律(不可违反)
- 先复用基线 MAP,再分析变更
- 模块路径白名单:当前模块只能使用白名单内文件生成新增用例
- 所有内容必须来自本次输入,禁止经验推断
- 每个功能点、每个步骤都必须有证据
- 只有通过质量门禁的变更,才允许进入 suggested_new_cases
- 反例自检不强制凑数:`rejected_considered` 输出 0-3 条有证据的否决项
这套铁律把 AI 的输出分成几条线:能拿出证据的,写成增量功能点和新用例;只是影响到已有用例的,回写原用例;后端改了但找不到前端入口的,归进提醒;证据不足或不值得写的,直接拒绝。下面的 JSON 只是节选,完整输出还会带上功能点清单、受影响用例、质量门禁说明等字段:
{
”module”: ”智能体”,
”quality_gate”: {
”can_generate_cases”: true,
”reason”: ”存在明确 UI 入口且步骤证据完整” },
”changed_feature_map”: [
{
”feature_id”: ”CF-1”,
”sub_feature”: ”智能体市场详情页返回按钮”,
”change_type”: ”修改”,
”case_generation_decision”: ”generate”
},
{
”feature_id”: ”CF-2”,
”sub_feature”: ”DashScope 嵌入器并发优化”,
”change_type”: ”后端逻辑”,
”case_generation_decision”: ”backend_alert”
}
],
”suggested_new_cases”: [
{
”source_feature_id”: ”CF-1”,
”用例名称”: ”智能体市场详情页返回按钮——返回原列表状态”,
”功能模块”: ”智能体-市场”
}
],
”rejected_considered”: [
”DashScope 并发数上限边界值测试 → 属于后端算法层,无 UI 触发路径”
]
}
工程师扫这份结果时,不再是”读一大段长文案、再猜作者想说什么”,而是顺着这份结构逐块确认:变更地图看边界划得对不对,新用例建议看步骤和证据齐不齐,后端提醒看要不要补一个前端入口,否决清单看有没有漏掉重要场景。
第二层:从”场景描述”到”可执行脚本”
痛点
在 Vibe Coding 这种开发模式下,有一个绕不过去的现实:AI 经常会”改错东西”。它为了完成一个需求改动一处代码,却因为缺乏全局上下文,顺手碰坏了另一个看似无关的功能——系统越复杂、团队越大、每天合入的改动越多,这种”意外回归”就越频繁,再加上功能迭代快,所以日常回归必须自动化,否则根本不知道今天又有哪个旧功能被悄悄改坏了。
当然,自动化不可能、也不需要覆盖全部用例——复杂 UI 交互、视觉效果、探索性场景仍然靠手工;但核心业务流程的接口回归最值得、也最适合稳定脚本化,把它交给自动化每天跑。真要写好自动化第一道坎从来不是”不会写代码”,而是搞清楚业务流程中数据怎么流转——创建一个知识库需要先调哪些接口?上传文件后要轮询多久?文档解析完成的标志是什么?这些信息散落在前后端代码的各个角落。
实现(以API测试为例)
我们设计了一套两阶段流水线:先用 AI 生成测试场景设计(我们叫它 Story),人工确认后,再用 AI 把 Story 翻译成可执行的测试脚本。
AI 做的事情:
- 第一阶段,Story 生成:根据测试工程师给的一句话输入(比如”知识库文档分块策略”),AI 扫描前端组件、API 路由、后端服务,输出一份结构化的 Story 文件——含测试步骤、验证点、数据流闭环、清理策略。
- 第二阶段,脚本生成:Story 确认后,AI 把它翻译成可直接执行的 Postman Collection。每个 Collection 完全自包含——自带登录、组织激活、数据创建和清理,不依赖其他文件的执行结果。几十个 Collection 可以任意组合、任意顺序执行。
AI 做不了的几件事:
-** 关键输入**:“知识库文档分块策略”这七个字,背后是测试工程师对产品的判断:这个功能的风险在哪里?用户最容易踩的坑是什么?哪些边界条件必须覆盖?AI 只是把这个判断”展开”成具体的测试步骤,但方向是人定的。
- Story 审查:小部分 Story 会被工程师要求重新生成或大幅修改。这类判断来自工程师对场景和 API 测试步骤的审阅。
- 架构约束:“每个 Collection 自包含”、“按耗时和资源依赖分组”——这些设计决策来自工程师从过去”测试有隐式依赖”的惨痛经历里提炼的教训。约束是人带进来的,AI 按约束生成代码。
实操示例
第一阶段的核心是用一条指令唤起 AI 的”测试覆盖漏洞”自查心态。这是我们 /test-story 命令的开场:
你是一名以「测试覆盖漏洞」为耻的 QA 工程师。生成 Story 之前,
你的第一反应是”这个功能有哪些维度我可能没想到?”——在所有
执行步骤开始前保持这个视角。
输入:模块名 + 场景描述(如:智能体调度 广播调度-多角度评审)
执行:
1. 并行扫描前端组件、API 路由、后端服务
2. 做场景分类与测试覆盖分析——逐一判断本场景是否包含:
A. 参数配置层(等价类划分 + 正交法)
B. 状态流转层(状态转换测试)
C. 规则判断层(判定表)
D. 业务流程层(场景法)
E. 边界与异常层(边界值 + 错误推测)
存在的层次做完整分析,未覆盖项写入”遗留说明”
3. 输出结构化 Story 文件
“测试覆盖漏洞为耻”这一句很关键——它让 AI 在生成场景时主动做”我漏了什么”的反思,而不是只罗列显而易见的步骤。AI 据此输出的 Story 是这样的(节选):
---
id: S-AGENT-005
module: 智能体
feature: 跨组织同步
scenario: 协调者 syncSubAgents true/false 子智能体同步行为
---
## 测试覆盖地图
### A. 参数配置层
- 因子1:syncSubAgents(true / false 全覆盖)
- 因子2:子智能体数量(0 / 1 / 2+ —— 本 Story 覆盖 2)
### E. 边界与异常层
- 源协调者无 active version 时的拒绝路径
- 目标组织 schema 名冲突时的覆盖策略
第二阶段把 Story 翻译成 Postman Collection,每个 Collection 自包含(自带登录、组织激活、数据准备),互相独立可任意编排——这是测试工程师从过去”测试有隐式依赖”的惨痛经历中沉淀的约束,AI 只是按约束去生成。最终几十个 Collection 的全量回归每天在 CI/CD 中运行。
第三层:站在第二层之上,让性能问题别等到上线前
痛点
前两层从功能角度确定了”测什么、怎么测”。但功能正确不等于扛得住压力——这一层要回答的是”扛不扛得住”。它能轻量落地,靠的正是第二层:业务流程已经沉淀成可复用脚本,把它延伸成压测几乎零成本。所以这一层真正要想清楚的,不是”怎么写脚本”,而是什么时候做。很多团队的非功能测试是这样安排的:版本快发布了,搭一套 HA 环境,跑一轮压测,出报告。问题不在工具,在时机。发布前才做,发现问题已经是最后一公里——这时候改,问题已经变得更复杂,重则要动架构,代价是迭代早期的几倍。
我们需要的不是一次更大的压测,而是把非功能验证嵌进日常迭代——每隔一段时间跑一遍,让问题暴露在它最容易修的时候。
实现
我们基于 k6 搭了一套日常化非功能测试,重点覆盖三类场景:少量用户并发、数据持续积累、突发活动流量。AI 在这一层的角色比前几层”轻”,但它省下了从零写脚本的力气——不是凭空生成,而是站在第二层已经沉淀好的”业务流程地图”上做改造。
AI 做的事情:
- 读取已有 API 测试脚本作为参考:第二层智能体已经把登录、组织激活、上传文档、轮询解析、发起对话等业务流程梳理清楚了——这些 Postman Collection 就是 AI 编排 k6 脚本时最好的”业务地图”。
- 按测试场景编排脚本:测试工程师给出场景描述(“5 人并发跑知识问答”),AI 把已有流程改写、串接、参数化成 k6 脚本。
- 复用而非创造:这一层 AI 的核心价值不是凭空生成,而是把功能测试积累下来的业务流程改造成并发压测的形态。如果没有第二层的积累,AI 在这一层会很难下手。
AI 做不了的几件事:
AI 编排出来的 k6 脚本只是骨架,真正考验工程师判断力的从这里开始——
- 场景建模:哪些操作要串在一起?模拟 30 人参加大赛、30 人日常使用、30 人活动结束后查询历史——三种场景压力曲线完全不同。AI 不懂业务场景背后的人的行为模式。
- 判断接口响应时间退化是不是真问题:跑出来某个接口慢,是网络抖动?是数据积累?是某次变更引入了性能回归?
- 决定 Bug 要不要拦版本:测出来的问题不一定都是发布阻断项——有的影响很小、用户无感;有的影响较大、但临近发布窗口改动风险更高。这个取舍是产品判断,不是技术判断,AI 给不了答案。
实操示例
测试工程师给 AI 的指令很短,关键在于点出”复用已有工具”:
基于 nftest/concurrent-load/utils/ 中已封装的工具
(auth.js 登录、chat.js 创建会话/发送消息/解析 SSE),
编排一个 RAG 并发场景:
- 5 个 VU,每个跑 10 轮问答
- 不同 VU 用不同账号(从 RAG_USERS 用户池取)
- 问题从 RAG_QUESTIONS 池子里循环取
- 输出到 scenarios/rag.js
AI 据此输出的脚本,直接复用第二层封装好的业务流程,把功能测试形态改造成并发压测形态:
// scenarios/rag.js —— RAG 并发场景
import { login } from '../utils/auth.js';
import { createThread, sendMessage } from '../utils/chat.js';
import { RAG_USERS, PASSWORD, RAG_QUESTIONS, ENDPOINTS } from '../config/config.js';
export function runRAGScenario(context) {
const rounds = parseInt(__ENV.ROUNDS || '10', 10);
const email = RAG_USERS[context.vu.idInInstance - 1];
const cookie = login(email, PASSWORD); // ← 复用第二层
const threadId = createThread(cookie, 'builtin:rag'); // ← 复用第二层
for (let round = 0; round < rounds; round++) {
const question = RAG_QUESTIONS[round % RAG_QUESTIONS.length];
sendMessage(cookie, ENDPOINTS.RAG_CHAT, threadId, question); // ← 复用第二层
}
}
没有第二层这些封装好的工具,AI在这里会很难下手——它要从零研究 k6 的 VU 模型、SSE 解析、用户池隔离。复用第二层的沉淀,反而是这一层最大的价值。
性能问题最怕的是”晚发现”。日常跑、小步快跑、和开发一起盯指标,才是AI时代非功能测试的正确姿势。
**结语:AI 承担得越多,判断和责任越在人 **
这套体系,让我们的测试节奏跟上了AI时代的开发节奏。但翻回每一层便会发现,最要紧的那几步始终留给了人:AI能沿着既定思路高速推进,然而思路从何而来、推进到何处应当收住,仍需有人了然于心。
因此,我们渐渐不再纠结”AI会不会取代测试工程师”。它做得越多,测试工程师越是从一条条写用例、一遍遍跑回归中抽身,转向立标准、作判断、担责任这些更吃重的事。这不是取代,而是各司其职。
工具会愈发聪明,能替我们分担的测试工作也只会越来越多;但测得够不够、能不能放行,为产品质量把最后一道关的,始终是人。