在接口测试这个行当里待了十几年,我最怕听到的一句话就是“这个我测过了,正常流程没问题”。说这话的人大概率没测异常流——不是不想测,是真的写不出来那么多。
最近半年我一直在做一件事:把异常流用例生成这件事交给大模型,让AI模拟用户的各种错误输入,自动产出异常流测试用例。目前在我们团队的核心服务接口上跑了几轮,效果比想象中好不少,也踩了不少坑。今天这篇就把完整的思路、提示词、实操流程和踩坑记录都摊开讲讲。
这篇内容适合谁?如果你是测试工程师、测试开发,或者正在做AI测试和AI自动化测试方向的产品经理,看到这篇文章可以直接照着抄作业。如果你只是好奇AI到底怎么帮人写用例,也能当一篇不错的实战案例看。
1. 为什么异常流用例最值得让AI来补
1.1 传统异常用例挖掘到底难在哪
先说结论:正常流程用例是“写”出来的,异常流用例是“挖”出来的。
正常流程就那么几条,登录成功、下单成功、支付成功,每条都是确定性的,照着需求文档写就行。异常流不一样,它要回答的问题是“用户会怎么把这件事搞砸”。搞砸的方式实在太多了——类型不对、长度超过边界、格式非法、字段缺失、字段多了、枚举值超出范围、特殊字符注入、依赖服务超时、重复提交、并发覆盖……
传统的设计方法等价类划分和边界值分析确实能覆盖一部分,但遇到字段一多的接口就非常吃力。我给你算一笔账:一个创建订单的接口,假设有12个入参字段,每个字段有类型异常、长度异常、格式异常、枚举异常、缺失、为空六种情况,理论上就有72条基础异常输入。这还只是单字段的玩法,还没算字段组合异常、业务依赖异常、状态冲突异常。人肉写这些用例,写不了几条就会开始烦躁,一烦躁就漏。
更麻烦的是,异常用例需要一定的“想象力”。有经验的测试会琢磨“用户会不会在金额里传负数”“会不会往手机号里塞一个HTML标签”“会不会在备注里贴一长串emoji”。这些想象力本质上是测试人员见过的坑的积累,新人根本做不到,老人又没有时间每次都把脑洞铺满。
1.2 大模型做这事儿的底层逻辑
大模型被用来做异常用例生成,底层逻辑其实很简单:它见过足够多的人类错误。
你可以在提示词里告诉它“这是一个创建订单的接口,请你模拟真实用户可能犯的各种错误输入”,它就能凭训练时见过的海量接口文档、Bug报告、测试用例、用户反馈,把那些“人类经常干的事”迁移过来。这本质上是一种经验驱动的内容生成,和之前用规则模板生成异常数据完全不是一个量级。
关于“AI模拟用户错误输入”这个点,我要特别说一下:AI的厉害之处在于它能生成有语义的错误,不是纯随机的乱码。比如你问它“下单时quantity字段传什么能触发异常”,它给出来的可能是负无穷、浮点数0.5、字符串“1e3”、超长数字串、null、空字符串、数组类型的[1,2,3]。这些值是有人类错误逻辑在背后的,而不是随便让你输一串乱码去碰运气。
对比一下传统的模糊测试(Fuzzing),它也会生成一堆异常输入,但绝大多数是没头没脑的字节流,命中率低,可读性差,跑挂了你还得慢慢猜是哪个片段把它打崩的。大模型生成的异常输入是“能看懂”的,每条都有场景描述和预期结果,可以直接转成用例,这也决定了它在测试设计领域的位置——它不是替代模糊测试,而是在更高一层做可解释的用例设计。
1.3 边界:AI能补什么,不能补什么
这里必须泼一盆冷水:AI生成异常流用例不是银弹。
我的实践结论是,AI擅长的部分是输入域的异常——字段类型、长度、格式、枚举、组合、空值、特殊字符这个方向。它不擅长的是业务时序异常。比如“先退款后发货”“两个请求同时改同一份数据”“订单在已关闭状态下又被取消”这类需要理解状态流转和并发场景的异常,大模型很难只凭一句接口描述就设计出来,因为它看不到你们系统的完整业务状态机。
所以我在团队里定的调子是:AI负责把输入异常的量铺满,人工负责设计状态与业务逻辑层面的异常流。两条线合并起来,才算一套完整的异常用例体系。
2. 工具选型与提示词工程:让大模型“像人一样犯错”
2.1 模型选择:我实测下来怎么选
做这个方向之前,我花了两周时间对比不同大模型API的效果,主要评估这几个指标:生成异常输入的多样性、输出JSON的稳定性、中文场景的理解力、接口响应速度和成本。
我个人的选型结论是这样的:
| 模型 | 上下文能力 | 结构化输出稳定性 | 中文理解 | 成本/性价比 | 我的评价 |
|---|---|---|---|---|---|
| GPT-4系列 | 强 | 强 | 好 | 偏高 | 综合最强,适合复杂接口 |
| Claude系列 | 强 | 中上 | 好 | 偏高 | 长文本友好,但偶尔输出格式飘 |
| DeepSeek系列 | 强 | 中上 | 好 | 较低 | 中文场景性价比高,我主力用这个 |
| 通义千问系列 | 中 | 中 | 好 | 低 | 稳定够用,适合预算敏感团队 |
选模型有一个容易被忽视的点:不要只看生成质量,还要看它对结构化输出的服从度。异常用例最终是要落进测试平台或者转成自动化脚本的,如果AI动不动在JSON里夹带私货——比如多一段解释文字、用中文代替true/false——后处理成本会高到让你怀疑人生。实测下来,DeepSeek和GPT系列在“你说要JSON就给你纯JSON”这件事上表现最稳。
顺便说一句,如果你团队里有人问API的Credits到底是什么——Credits就是大模型API的额度,每一次请求都按输入输出的Token数消耗Credit。批量生成用例之前,先掂量一下每天烧多少Credits,这玩意看着单价便宜,用例量一旦上来了,费用也是肉眼可见在走的。
2.2 提示词模板:一个好的异常用例生成Prompt长什么样
提示词是整个方案里最值得琢磨的部分。好的提示词可以让AI输出的异常用例直接可用,烂的提示词生成出来的东西一万条里能用的不超过两位数。
我调整了很多版,最后稳定下来的是这三段式结构:
第一段,角色设定和任务定义。明确告诉模型它是一个资深测试工程师,正在为指定的接口设计异常流测试用例。这一段的目的是把模型的“人设”拉到一个懂测试的位置上,它后面给出来的预期结果才不跑偏。
第二段,接口契约与参数约束。模型对字段类型和业务含义的理解完全来自这一段,所有字段名、类型、是否必填、枚举范围、长度上限都要写清楚。我习惯直接用JSON格式把字段定义贴进去,结构化描述比自然语言描述准确得多。
第三段,错误输入类型清单和输出格式约束。最关键的技巧是:不要笼统地说“请生成异常用例”,而是把异常类型枚举给AI看,比如“类型错误、空值、超长、非法枚举、SQL/HTML注入、负数、特殊字符、语义冲突”,AI一旦有了方向,生成的东西会精准很多。
输出的格式我用的是JSON数组,每个测试用例包含场景名称、异常输入数据、预期结果、预期状态码、错误描述五个字段。下面贴一个我常用的模板,可以直接抄:
{ "task": "你是一名资深测试工程师,请为以下接口生成异常流测试用例。", "interface": { "name": "创建订单", "method": "POST", "path": "/api/order/create", "params": [ {"name": "userId", "type": "string", "required": true, "desc": "用户ID", "maxLength": 32}, {"name": "productId", "type": "string", "required": true, "desc": "商品ID", "maxLength": 32}, {"name": "quantity", "type": "integer", "required": true, "desc": "购买数量", "min": 1, "max": 99}, {"name": "couponId", "type": "string", "required": false, "desc": "优惠券ID", "maxLength": 32}, {"name": "remark", "type": "string", "required": false, "desc": "订单备注", "maxLength": 200} ] }, "errorTypes": ["类型错误", "字段缺失", "空值", "超长", "非法枚举", "负数/零", "特殊字符注入", "SQL/HTML注入", "字段组合冲突"], "outputFormat": "返回JSON数组,每个元素包含{sceneName, abnormalInput, expectedResult, expectedStatus, errorDesc},只输出JSON,不要额外说明。", "fewShot": [ { "sceneName": "quantity传负数", "abnormalInput": {"userId": "u_001", "productId": "p_001", "quantity": -1}, "expectedResult": "下单失败,提示数量不合法", "expectedStatus": 400, "errorDesc": "数量字段为负数,超出业务允许范围" } ] }每个字段的maxLength、min、max这些约束一定要给全。AI不是你们系统的开发者,你不在提示词里告诉它“quantity不能超过99”,它就永远不知道生成一个100的越界值。
2.3 采样参数:Temperature对“犯错的离谱程度”影响很大
大模型API里有个参数叫Temperature,通俗点说就是生成时随机性的高低。温度越低,输出越保守稳定;温度越高,输出越天马行空。
用AI生成异常流用例这件事上,Temperature对结果质量的影响非常大。我专门做过一组对比实验:
Temperature在0.2以下的时候,生成的异常场景高度趋同,翻来覆去就是“传空字符串”“传null”“传一个不存在的ID”,多样性很差,基本没法用。Temperature在0.7到1.0之间的时候,效果最好,AI既能保持格式稳定,又能在错误输入上玩出花——超长字符串、HTML标签、emoji、中英文混杂、嵌套JSON都出来了。Temperature超过1.2之后,AI开始放飞自我,经常编造接口里根本不存在的字段,或者给出一段完全看不懂的预期结果。
所以我把Temperature固定在0.8左右。你们接入的时候也建议在0.7到1.0之间调一调,不同模型对温度的敏感度不一样,最优值要自己拿典型接口跑两轮再定。
3. 实操全过程:从接口契约到异常用例自动执行
3.1 第一步:把接口契约喂给模型
不管你是直接在对话页面手敲还是走API批量调用,第一步都一样:把接口契约整理干净。
我在项目里首选那些有Swagger/OpenAPI文档的接口,直接从文档里把参数定义拽出来,转成上节模板里的params数组结构。没有现成文档的接口,就找开发要一份字段清单,重点是每个字段的类型、是否必填、长度限制和枚举范围,这四样缺一不可。
有一个细节很关键:接口契约里那些不在入参列表里、但会出现在URL路径上的参数,比如/api/user/{userId}/orders里的userId,也要在提示词的接口描述里单独标出来。你如果不标,AI要么忽略它,要么把它跟body参数混在一起生成一个四不像的数据,两种情况都会浪费你的审核时间。
3.2 第二步:生成异常输入与用例清单
以我们真实项目里的下单接口为例,我按上面的模板调用大模型API,一次返回了15条异常用例。挑几条有代表性的给你们看看:
| 场景名称 | 异常输入 | 预期结果 | 预期状态码 |
|---|---|---|---|
| userId传超长字符串 | userId=“u_” + “A”*100, 其他正常 | 参数校验失败,提示用户ID格式错误 | 400 |
| quantity传浮点数 | quantity=1.5 | 下单失败,提示数量必须为整数 | 400 |
| remark传HTML标签 | remark=“ ” | 正常下单,但存储时须转义,不执行脚本 | 200 |
| couponId传不存在的ID | couponId=“coupon_not_exist_001” | 下单失败,提示优惠券不存在 | 400 |
| 组合冲突:优惠券ID与商品不匹配 | 传一张只适用于A商品的优惠券,下单B商品 | 下单失败,提示优惠券不可用 | 400 |
| 必填字段缺失 | 只传userId, 不传productId和quantity | 参数校验失败,提示商品ID和数量不能为空 | 400 |
| 超长中文备注 | remark=200个中文字符再拼接10个字符 | 截断或报错,按业务规则断言 | 400 |
这里我想重点说下“SQL/HTML注入”和“字段组合冲突”这两个类型的生成结果。人工写用例的时候,最容易漏掉的就是“把XSS攻击串塞到备注里”这类看起来不够“正经”的输入,但AI在训练语料里见过太多类似事故,你只要在errorTypes里点一下“SQL/HTML注入”,它一定给你生成出来。这就是AI模拟用户错误输入的价值——它把你“想不到”但“真实存在”的错误行为提前暴露出来了。
3.3 第三步:人工审核与去重合并
AI生成的用例不能直接进测试平台,一定要有人过一遍。这一步最容易被省略,但恰恰是决定方案质量的分水岭。
我在审核的时候按三个维度去查:
第一,查幻觉字段。AI偶尔会生成一个接口定义里不存在的字段,比如给下单接口加一个orderId——单子还没创建,哪来的orderId?这种用例直接删除。
第二,查预期结果是否合理。AI给出的预期结果描述有时候跟你们接口真实的返回结构对不上。比如它预期错误码是400,但你们后端自定义了统一的错误码格式{"code": 50001, "msg": "..."},预期字段对不上没关系,关键是错误语义要一致。
第三,查边界覆盖是否完整。手工过一遍AI生成的用例,重点看数值型字段的边界值(最小值、最小值-1、最大值、最大值+1)有没有覆盖到。AI正常情况下能覆盖大部分边界,但偶尔会漏,人工补一下就行。
重复用例的处理也很讲究。AI经常生成“quantity传0”和“quantity传-1”这样两个用例,语义不能算重复,因为一个是零边界,一个是负数异常;但“quantity传字符串abc”和“quantity传字符串xyz”就是重复的,留一条就行。我建议按“每个字段每种异常类型保留一条”的原则去重,再结合场景语义判断,不要简单看数值一样就删。
3.4 第四步:把用例批量转成可执行脚本
审核通过后的用例,我通常转成pytest加requests的自动化脚本,数据驱动跑一遍。这里贴一下核心代码,非常简单,就是一个循环执行器:
import pytest import requests BASE_URL = "https://api.example.com" # 异常用例列表,从AI生成结果中筛选后导入 TEST_CASES = [ { "name": "quantity传负数", "payload": {"userId": "u_001", "productId": "p_001", "quantity": -1}, "expected_status": 400, "expected_error": "数量不合法" }, { "name": "userId传超长字符串", "payload": {"userId": "u_" + "A" * 100, "productId": "p_001", "quantity": 1}, "expected_status": 400, "expected_error": "用户ID格式错误" } ] @pytest.mark.parametrize("case", TEST_CASES, ids=lambda c: c["name"]) def test_abnormal_order_create(case): resp = requests.post(f"{BASE_URL}/api/order/create", json=case["payload"]) assert resp.status_code == case["expected_status"] assert case["expected_error"] in resp.text如果要接CI,就在流水线里加一个步骤,每天早上跑一遍异常用例集。还可以用平台把用例管理起来——我们调研的时候看过TestBuddy这类用例生成与管理工具,也能和异常用例结合使用,前端录入AI生成的场景,后端自动执行并回填结果。
我们团队里现在普遍用Cursor这类AI编程工具辅助写用例执行器。你只要把一条用例的JSON贴给它,让它生成对应的pytest测试函数,几秒钟就出来了,写脚本的时间几乎可以忽略不计。AI生成用例、AI生成脚本、人来审核和执行,整条链路跑下来非常顺。
4. 常见问题与踩坑实录
4.1 症状一:生成的异常值“不够异常”
第一次跑这个方案的时候,AI返回的用例几乎是清一色的“传null”“传空字符串”“类型传错”,所有的异常输入看起来都像一个模子里刻出来的,没有任何惊喜。
排查下来发现原因在于提示词里没有给足“错误类型指引”。你光说“请生成异常输入”,AI就会按训练数据里最常见的写法来,而那些最常见的一定是最简单的那几种。后来我在提示词里加了一个错误类型清单,并且明确要求“每个错误类型至少生成一条用例”,多样性立刻上来了。再后来我进一步在few-shot里给了一个稍微不那么常规的示例(比如quantity传浮点数),AI的输出质量又上了一个台阶。
这个问题的本质是“你要给AI一个错误输入的方向,它才能在你的方向里发挥创造力”。不要指望AI凭空替你发明错误类型,它的创造力更擅长在给定类型下制造变体。
4.2 症状二:模型在“编字段”,幻觉跑偏
有几次AI生成的用例里出现了接口根本没有的字段,比如下单接口里多了个discountDetail,这明显是模型自己脑补的。这种用例一旦混进自动化脚本,请求发出去会被后端的序列化直接忽略,但它会让测试结果产生虚假的“通过”——因为错误根本没触发,请求却返回了200。
解决这个问题我用了两个办法。一是提示词里硬性约束“只能使用接口定义中的字段,不得新增任何字段”,把它加在输出格式要求里。二是在后处理脚本里加一道程序化校验,凡是请求体里的key不在接口契约字段集合里的用例,直接丢进待审核列表。这两道关卡一上,幻觉字段进不了执行环节。
说到AI幻觉,这个方向上也别太较真——AI生成的异常用例本质上就是候选集,所有用例都要经过人或程序校验才能执行。你只要把“防幻觉”做成一道自动校验关卡,就不会被这个问题困扰。
4.3 症状三:输出格式时好时坏
用AI生成用例走API批量调用的时候,最怕的就是格式不稳定。我遇到过模型在JSON数组后面追加一段“注意:以上用例仅供参考”的注释,也遇到过把某个日志误标成true而不是true。
这问题靠提示词硬约束只能解决八成,剩两成要靠代码兜底。我写了一个后处理函数,用JSONSchema先校验一遍,解析不通过就自动重发一次请求,连续三次解析失败就把这条原始响应单独存起来人工看。再加一个关键词检测,把“注意”“特别说明”“此外”这些高频尾巴词后面跟着的文本一律截断删掉。实测这样处理后格式有效率达到98%以上。
说起这个,我不建议把AI的输出直接当JSON去解析——一定要经过清洗和容错。测试领域讲究的是稳定可复用,AI输出那一层你就当它是一个“有点絮叨的实习生”,干活能力还行,偶尔话多,你得有个聪明的编辑器帮它收拾残局。
4.4 症状四:批量生成到后半段,质量断崖式下降
批量调用API生成用例,跑了几十次之后返回到前面几批质量还行,后边生成的结果开始重复,甚至有的调用直接返回空数组。这个现象跟模型的上下文处理方式和配额限制都有关系,解决思路也简单:分批控制,每次只让AI生成10到15条,用完一个请求就结束,不要让它在一次对话里连续生成太多。
我现在的做法是:按字段或按异常类型分桶,比如“这一批专门生成quantity字段的异常用例”“这一批专门生成remark字段的注入用例”,每批限定数量。这样既避免模型在开放域里瞎逛,又让单批质量完全拉满。
成本控制上也要留个心。批量生成1000条用例,如果按Token计费敞开了跑,费用并不便宜。按异常类型分桶还有一个额外的好处:容易估算Token消耗,遇到大接口可以先按桶切好,跑多少用多少,不会中途失控。
5. 效果与投入产出:值不值,我说说真实的数字
5.1 一个真实项目的落地数据
我们团队在一个核心交易链路的服务上完整跑了一个月的AI异常用例生成,具体数据是这样的:覆盖接口32个,AI生成异常用例1280条,经过人工审核和去重后保留有效用例876条,命中真实Bug的用例有23条。不要小看这23条,里面有5条是线上事故级的隐患,比如订单金额字段精度丢失、优惠券状态校验缺失导致可重复使用等。
效率方面的提升更直观。原来纯人工设计异常用例,一个中等复杂度的接口大概要写两个小时,还不能保证覆盖完整;现在AI生成加人工审核,同样一个接口平均40分钟搞定,其中一半时间还是花在执行和确认预期结果上。整体效率大概提升了6成以上。人工的价值从“闭门造车设计用例”转变成了“审视和判断AI设计的用例”,这个转变对测试人员来说其实是好事——从体力劳动转向了脑力劳动。
5.2 三种落地姿势:从轻量到深度集成
这套方案在团队里的落地方式,我推荐分三步走:
第一步,轻量试用。不管你是用网页版聊天还是API调用,先把两三个高频接口的异常用例生成出来,手工执行一遍看看命中率,验证AI生成的内容在你们系统上是否真的能触发异常。
第二步,工具链整合。把提示词模板和后处理脚本固化成工具,支持输入一个OpenAPI文档片段,自动输出清洗后的JSON用例文件。这个阶段可以让QA都学会用,并把用例集纳入版本管理。
第三步,平台与CI集成。把用例执行器接到你们现有的测试平台上,用AI Agent定期自动生成增量异常用例,加进每日回归流水线。这是收益最大的阶段,也是工作量最大的阶段,建议前两步跑顺了再上。
如果你用的是TestBuddy之类的用例生产工具,也可以把AI生成的用例导入进去统一管理,让工具本身承接用例的组织和生命周期管理,AI只负责“生产原料”。这样整条链路的每一环都是可替代、可扩展的。
5.3 局限与建议:别指望AI包办一切
最后坦白说几个当前方案的边界。
第一,AI生成的异常用例集中在输入参数层面,对业务状态异常、分布式一致性异常、缓存与数据库不一致这类深水区问题基本无能为力。这类用例还是得靠人工设计、靠架构师和资深测试的口口相传。
第二,大模型对你们业务规则的理解深度有限。比如“优惠券只能用于指定品类且与用户等级有关”这种复合规则,AI在提示词里没有明确信息的情况下是猜不出来的。所以用这个方案之前,把业务规则尽可能写进接口契约里,信息越全,AI的表现越好。
第三,任何AI生成的用例都需要回归到真实业务场景里验证。生成一条用例说“预期状态码400”很容易,但你们后端是不是真的返回400、返回的body是什么结构、错误信息用户能不能看懂,这些仍然需要人工确认一遍。AI做加法,人工做减法,这才是我理解的AI测试的正确姿势。
我在实际使用中还有一个特别想把你们拉坑里爬出来的经验:提示词里一定要加一句“如果某个字段在某个错误类型下无法构造有意义的异常输入,请用skip标记而不是硬编”。不加这句话,AI为了完成数量指标,会给一个枚举值本来就只有一个的字段强行编一个“非法值”,而这种用例十有八九是不成立的,还会浪费你审核的时间。加上这句之后,模型会老实告诉你哪些字段没有扩展空间,你反而能发现一些“这个字段是不是设计得过于狭窄了”的产品隐患。
这个方向我还在继续折腾,后续准备把业务状态流转图也结构化喂给模型,看看能不能在时序异常上啃下一块骨头来。项目里那些被AI预测出来真实Bug的明细,等有时间了再多写一篇复盘。