接了大模型生成测试用例后,我们统计了一周数据,发现人工还得改掉 40%
我们团队上个月把大模型接进了 Playwright 用例生成流程,跑了一周的真实业务模块后,统计出来的数字是这样的:模型一次生成的用例中,大约 60% 可以直接用或微调后可用,剩下 40% 需要人工大幅改写或直接丢弃。账面上看起来“省了 60% 的时间”,但算上审查、理解和重写的成本,实际净节省的开发时间只有 20% 出头。
这个数字比我们预期要低不少,也比市面上那些“AI 自动生成测试用例,效率提升 80%”的案例要保守得多。但它是我们自己业务场景下的真实数据,所以我决定把整个统计过程和拆解逻辑完整写下来。
我们接入大模型的方式和统计口径
先说清楚我们是怎么接的。团队用的是 Playwright 1.45,测试框架是 TypeScript 写的,模型侧接了两个:一个 GPT-4o(2024-08-06 快照),一个内部的 Qwen 72B 微调版,通过 LangChain 做了一层薄封装。触发方式不是全自动的——我们让模型在开发者写完一个页面组件、给出页面截图和 DOM 快照后,根据一份 15 条规则的 prompt 生成对应的测试用例。
统计的那一周,我们挑了三个业务模块:一个 SaaS 后台的用户权限管理、一个电商前端的购物车链路、一个数据看板的图表渲染验证。三个模块加起来,模型共生成 217 个用例,全部进入了人工审查。
我们的“可用”标准分三档:A 类——直接可用,连 selector 都不用改;B 类——逻辑正确但需要改 selector、调整等待策略或拆分步骤;C 类——逻辑错误、遗漏关键断言、或者生成的步骤根本无法执行。A+B 算“可用”,C 就是需要人工重写的部分。40% 这个数字,指的就是 C 类的占比。
为什么是 40% 这个数字,而不是 10% 或 80%
217 个用例里,A 类 51 个(23.5%),B 类 79 个(36.4%),C 类 87 个(40.1%)。这个分布其实挺说明问题的——模型不是完全不能用,但离“直接用”还有相当的距离。
拆开看每个模块的表现差异很大。权限管理模块的 C 类占比只有 22%,因为它的页面结构规整,角色-权限矩阵的逻辑模式固定,模型学得很好。购物车链路的 C 类占比飙到了 53%,主要问题出在状态管理上:购物车有大量的异步更新、库存校验、优惠券叠加计算,模型生成的用例经常漏掉中间状态,比如“加购物车后立即去结算”这种步骤,页面还没渲染完就执行下一步了。数据看板模块卡在 44%,图表渲染的断言写得一塌糊涂——模型不会验证 Canvas 或 SVG 的具体数据点,只会写 expect(page.locator('canvas')).toBeVisible() 这种没营养的断言。
这说明 40% 不是模型的固定能力上限,而是跟业务场景的复杂度强相关。你的页面越“标准”、交互模式越常规,模型表现就越好;一旦涉及复杂状态流转、异步时序或者非 DOM 渲染的内容,模型的产出质量就断崖式下跌。
人工改掉 40% 到底花了多少时间
光看比例还不够,我们更关心的是时间账。我们让三个模块的开发者各自记录了审查和修改用例的实际耗时,精确到分钟。
A 类用例的审查很快,平均每个用例 1.2 分钟,基本就是扫一眼确认没问题就过。B 类用例平均耗时 4.7 分钟,主要花在调整 selector 和等待策略上——模型经常生成 page.locator('.btn-primary') 这种脆弱的 selector,实际项目中 class 名是 CSS Modules 编译后的哈希串,必须改成 data-testid。还有一些 page.waitForTimeout(3000) 的硬等待,需要替换成 waitForResponse 或 waitForSelector 的精确等待。
C 类用例的处理时间就完全是另一回事了。平均每个用例要花 11.3 分钟,因为基本等于重写。而且这里有个隐藏成本:开发者先要花时间理解模型生成的错误逻辑,判断“它到底想测什么”,然后才能开始重写。这个理解成本平均占了 3-4 分钟,有时候比直接从头写还慢。
算总账:51 个 A 类用例审查花了约 61 分钟,79 个 B 类花了约 371 分钟,87 个 C 类花了约 983 分钟,总计 1415 分钟,约 23.6 小时。如果这 217 个用例全部由人工编写,按我们团队历史数据平均每个用例 9.2 分钟来算,总耗时是 1996 分钟,约 33.3 小时。实际节省了 9.7 小时,节省比例 29%,不是 60%。
而且这 9.7 小时的节省里,大头来自 A 类和部分 B 类用例的快速生成。C 类用例不仅没省时间,反而因为“理解+重写”的流程,比直接人工编写多花了大约 15% 的时间——87 个 C 类用例实际耗时 983 分钟,如果人工直接写只需要约 800 分钟。
模型在哪些地方最容易翻车
翻了一遍所有 C 类用例后,我们发现失败模式高度集中,主要有四类。
第一类是 selector 失效,占了 C 类的 38%。模型生成的 locator 在真实 DOM 里根本找不到元素。典型情况是前端用了 Shadow DOM,或者组件库动态生成的 aria-label 跟模型预期的不一致。有一个用例里模型写的是 page.getByRole('button', { name: '提交' }),但实际页面上按钮的文字是“确认并提交”,模型没拿到完整上下文。
第二类是时序问题,占了 31%。模型不理解异步操作的完成时机,比如生成一个点击“删除”按钮后立即检查列表长度的断言,但实际前端是先发 API、等响应回来再更新 DOM,中间有 200-400ms 的延迟。模型生成的代码里没有任何等待机制,断言必然失败。
第三类是断言质量差,占了 22%。大量用例的断言只检查元素是否可见,不检查数据是否正确。比如一个表格排序用例,模型只验证了“表头点击后页面没崩溃”,根本没验证排序结果对不对。
第四类是逻辑错误,占了 9%。这类最隐蔽,模型生成了看似合理的测试步骤,但测试的路径在业务上根本走不通。比如权限管理里,模型生成了一个“普通用户访问管理员页面”的用例,期望结果是跳转到 403 页面,但实际上我们的路由守卫在用户点击菜单前就把入口隐藏了,用户根本到不了那个页面。这类错误在审查时很容易被漏掉,因为步骤看起来太“正常”了。
prompt 优化能救回来多少
我们中间做过一轮 prompt 优化,想看看能不能把 C 类比例压下去。原版 prompt 是 15 条通用规则,优化后加到了 23 条,补充了项目特定的 selector 约定(必须用 data-testid)、等待策略要求(优先使用 waitForResponse)、以及断言的具体要求(表格排序必须验证数据顺序)。
优化后重新跑了购物车模块的 62 个用例,C 类占比从 53% 降到了 41%,B 类从 34% 升到了 48%,A 类基本没变。总可用比例从 47% 提升到了 59%,确实有改善,但离“好用”还有距离。而且 prompt 越写越长,维护成本也在上升——23 条规则已经开始互相打架了,比如“优先使用语义化 selector”和“必须用 data-testid”在某些场景下就是矛盾的。
我们的结论是:prompt 优化能改善边界情况,但解决不了根本问题。模型的局限在于它不理解你的具体业务上下文、不了解运行时环境、看不到真实的 DOM 结构,这些不是靠堆 prompt 规则能弥补的。
哪些场景适合让模型生成用例,哪些不适合
跑完这一周数据后,我们对“什么场景下用模型生成用例”有了更清晰的判断。
适合的场景有三个特征:页面结构标准化、交互模式简单、断言逻辑明确。比如表单校验、列表 CRUD、简单的权限控制,这些场景下模型的表现确实不错,A+B 类占比能到 75% 以上。
不适合的场景也有三个特征:复杂状态流转、非 DOM 渲染内容、需要精确时序控制的交互。购物车、实时数据看板、拖拽排序、WebSocket 推送更新,这些场景下模型生成的用例基本都需要重写,不如直接人工编写。
还有一个反直觉的发现:模型对“简单但繁琐”的用例生成帮助最大。比如一个表单有 20 个字段,每个字段有 3 种校验规则,人工写要写 60 个用例,重复劳动很多。模型生成这类用例又快又准,A+B 类占比能到 85% 以上。反而是那些“复杂但有趣”的场景,比如一个拖拽排序的边界情况,模型基本帮不上忙。
我们现在的做法:分层策略
基于这些数据,我们调整了策略,不再让模型无差别生成所有用例。
现在的流程是:开发者先花 5 分钟判断一个模块属于“标准型”还是“复杂型”。标准型模块直接让模型生成,人工只做审查和微调;复杂型模块只让模型生成数据准备和清理的辅助代码,核心测试逻辑全部人工编写。
这个分层策略跑了三周后,整体节省的开发时间稳定在 25%-30%,没有 60% 那么夸张,但稳定可预期。更重要的是,C 类用例的比例从 40% 降到了 18%,因为我们在源头就把不适合的场景排除了。
模型的定位也从“用例生成器”变成了“辅助工具”——它帮你写那些重复性高、逻辑简单的部分,复杂的核心逻辑还是得人来写。这个定位可能不够性感,但它真实。
常见问题
你们用的什么模型?换更好的模型能降低 40% 这个数字吗?
我们用了 GPT-4o(2024-08-06 快照)和 Qwen 72B 微调版,两个模型在 C 类占比上差异不大(GPT-4o 是 38%,Qwen 是 42%)。我们也试过 Claude 3.5 Sonnet 跑同一批用例,C 类占比 35%,有改善但不显著。问题不在模型能力上限,而在于模型拿不到运行时上下文——它看不到真实的 DOM、不知道前端框架的渲染时序、不理解业务规则,这些信息缺口不是换模型能解决的。
你们有没有试过给模型提供 DOM 快照或截图来改善 selector 问题?
试过。我们在 prompt 里附带了页面的 HTML 片段和全页截图,selector 准确率确实有提升,B 类用例的 selector 修改量减少了约 30%。但这也带来了新问题:HTML 快照如果太大,会超出模型的上下文窗口;截图里的文字如果跟 DOM 里的不一致(比如 Canvas 渲染的文本),模型反而会被误导。目前我们只在页面结构相对简单的模块里附带 DOM 快照。
40% 需要重写的比例,在行业里算高还是低?
没有行业标准答案,因为每个团队的“可用”标准不一样。我们了解到的情况是,做 Web 端测试的团队普遍反馈模型生成用例的可用率在 50%-70% 之间,跟我们 60% 的数据在一个区间。做移动端或 API 测试的团队数据会好一些,因为交互模式更标准化。如果你的页面大量使用 SSR、复杂状态管理或者非标准组件库,40% 的重写率完全正常。
审查模型生成的用例,会不会比直接人工写更累?
会,尤其是在你还不熟悉模型失败模式的时候。我们第一周的审查体验很差,开发者普遍反映“看模型写的烂代码比我自己写还累”。但跑了两周、总结了四类常见失败模式后,审查效率明显提升——开发者学会了快速扫描几个关键点(selector 是否用了 data-testid、有没有硬等待、断言是否检查了数据而不仅仅是可见性),C 类用例能在 2 分钟内判断出来是否需要重写。所以这个累不累,跟团队对模型失败模式的熟悉程度强相关。