大语言模型刚火起来那段时间,我所在的测试团队就在琢磨一件事:能不能让AI真正帮忙写测试用例,而不是停留在“给个样例、填个参数”的玩具阶段。试了大半年,从最初拿公开API跑简单接口用例,到后来把模型接进内部平台,让它在每次迭代里自动产出可执行的用例集,踩了不少坑,也梳理出一套还算能复用的方法。这篇文章就把我们走过的路、选型时考虑的问题、落地时遇到的坎,以及最终的实践方案完整写出来。
这个话题适合所有正在尝试用AI改造测试流程的人,不管是测试开发、测试经理,还是对AI落地感兴趣的后端工程师。我会尽量少讲空泛的概念,多给能直接在团队里试起来的东西。如果你正准备立项做“AI生成测试用例”,或者已经试过但效果不理想,这篇文章应该能帮你少走几个月的弯路。
1. 内容整体设计与思路拆解
1.1 为什么测试用例生成偏偏要靠大语言模型
先聊一个更底层的问题:测试用例生成的难点到底在哪。
以前我们常用的自动生成手段无非三类。第一类是模板填充,定义一个用例模板,把参数、预期结果占位符替换进去,适合重复度极高的接口测试,但一旦业务逻辑复杂,模板就撑不住了。第二类是基于代码分析的路径覆盖,用静态分析或者符号执行去枚举分支条件,这在单元测试层面有一定效果,但到了接口级、业务级的用例设计,代码结构根本不足以表达业务语义。第三类是录制回放,把线上请求录制下来变成回归用例,实话说这个很实用,但它只能覆盖已经发生过的场景,没法生成还没发生但应该被覆盖的场景。
这三类方法的共同问题是:它们都不理解“业务”。一次下单、一次退款、一次优惠券叠加,这些行为中哪些边界值得测、哪些组合容易出问题,靠代码结构和历史数据是推导不出来的。而大语言模型在大量代码、技术文档、业务文案上预训练过,它对“一个电商下单流程大概要考虑什么”是有先验认知的。这恰恰补上了传统方法的短板——它能从语义层面理解被测对象,然后把这种理解转化成用例。
所以大语言模型不是来替代传统用例设计的,它是来补足“业务语义理解”这一层的。
1.2 从“让AI写用例”到“AI真正改变用例生产方式”
我们团队立项之初,目标很朴素:让模型读接口文档,吐出一份可执行的接口测试用例。后来发现,这只是最浅的一层。真正产生价值的,是后面这几件事:
第一,模型可以把自然语言的需求描述直接映射成测试场景。比如产品文档里写“用户可以在购物车中批量删除已失效的商品”,模型能自动拆解出正常删除、部分失效、全部失效、空购物车、未登录等场景,再为每个场景补充边界值。这个能力在传统方法里几乎没有对应的实现路径。
第二,模型可以作为用例评审的“另一双眼睛”。我们经常让模型对比开发代码变更和已有用例集,找出被遗漏的影响面。这个用法严格来说不是“生成”,但它的价值甚至比“生成”更大,因为它的输出是基于对代码变更的理解,而不是凭空想象。
第三,模型可以自动生成测试数据构造逻辑。接口用例跑起来需要前置数据,以前都是手工准备,现在可以让模型根据字段约束生成数据构造脚本。这一块在我们项目里落地效果最稳定,产出直接能被自动化框架消费。
这也是为什么我觉得“基于大语言模型的测试用例生成”这个方向的本质,不是单点替换“人写用例”这个动作,而是把“理解需求—拆解场景—构造数据—生成断言—维护更新”这一整条链路全部重新做了一遍。
1.3 什么样的团队适合引入这套方案
AI生成测试用例不是银弹,它有自己的适用边界。根据我这段时间的观察和实际经验,下面这几类团队接入后收益最大:
- 接口数量多、迭代节奏快的团队。每轮迭代手工补充接口用例耗时最长,AI生成可以把“从0到1”的时间压缩到原来的三分之一甚至更短。
- 业务规则复杂、历史用例覆盖不足的团队。模型能从文档和代码中提取出人容易被忽略的边界场景,对存量接口做一轮“查漏补缺”效果很显著。
- 有自动化执行链路、但用例设计能力集中在个别资深同事身上的团队。把资深同事的用例设计思路沉淀成提示词模板,相当于把个人经验变成团队资产。
反过来,如果你的团队连基础自动化都没有,接口文档也不维护,那我建议先把地基打好再上AI。模型输出质量上限,取决于你输入给它的信息质量,这个在后面会展开讲。
2. 方案选型:API调用还是本地部署,模型怎么挑
2.1 先想清楚边界条件,再选模型
聊选型之前,先把一个最常见的误区说破:不是越大的模型就越好,也不是所有人都需要本地部署。选型之前,先回答下面这些问题:
- 测试数据是否涉敏?如果被测系统是金融、医疗、内部管理系统,数据一旦出网就可能违规,那基本只能选本地部署。
- 用例生成频率有多高?如果是每天持续集成触发,每次生成上千条用例,按Token计费的API成本可能会让你肉疼。
- 团队有没有GPU资源?本地部署不是下载个模型就行,推理服务需要显存、CPU、内存的持续投入,这个成本要算进项目的TCO里。
- 需要生成的用例类型是什么?纯接口用例、单元测试用例、端到端流程用例,不同类型对模型代码能力的要求差别很大。
我们把这几个问题写在立项文档第一页,每次纠结“要不要换模型”时都先回顾一下。踩过一次坑才明白:不先定边界,后面大概率会反复折腾。
2.2 模型选型:参数规模、能力侧重和硬性限制
说几个我们实际对比过的方案。如果数据允许出网,直接调商用API是最省事的路径。商用模型的泛化能力、指令遵循能力普遍强于同参数量的开源模型,尤其在处理长文档、复杂指令时差距明显。我们最开始用商用API跑接口文档生成用例,效果就已经能用了。
如果必须本地部署,那模型选型就要看硬件条件了。我们团队实测过几款主流开源模型,简单整理如下:
| 模型 | 参数规模 | 推荐显存 | 代码能力 | 中文理解 | 部署难度 |
|---|---|---|---|---|---|
| Qwen2.5-Coder | 7B~32B | 16GB~64GB | 强 | 强 | 低 |
| DeepSeek-Coder | 6.7B~33B | 16GB~64GB | 很强 | 中上 | 中 |
| ChatGLM3 | 6B | 12GB~16GB | 中 | 强 | 低 |
| CodeLlama | 7B~34B | 16GB~64GB | 强 | 弱 | 中 |
我们实际的测试结论是:如果只能选一个7B级别的模型跑接口用例生成,Qwen2.5-Coder-7B的性价比最好,中文接口文档理解得比较准,输出JSON格式的稳定性也够用。如果是复杂业务规则拆解,最好上14B以上的模型,效果差距还是比较明显的。
有一个坑要特别提醒:很多模型自称“代码能力强”,但“写代码”和“设计测试用例”是两回事。用例生成需要模型理解被测系统的业务上下文、识别边界条件、组织测试步骤,这跟“根据注释写一个排序函数”难度不在一个量级。所以选型时不要只看代码榜,要拿自己的接口文档和业务需求去实测,让模型真正生成一批用例再判断。
2.3 本地部署:一条可复现的落地路径
考虑到不少团队有数据隔离要求,我把我们本地部署的路径整理一下。我们用到的工具是Ollama和vLLM两个方案。Ollama胜在简单,一条命令就能把模型拉起来,适合小规模试跑;vLLM的吞吐量更高,适合持续集成场景下频繁调用。
以vLLM部署Qwen2.5-Coder-14B为例,我们的启动配置大概是这样的:
python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-Coder-14B-Instruct \ --host 0.0.0.0 \ --port 8000 \ --tensor-parallel-size 2 \ --gpu-memory-utilization 0.9 \ --max-model-len 32768几个参数说下理由。tensor-parallel-size设成2是因为我们用了两张卡,把模型切分到两张卡上推理;gpu-memory-utilization设0.9是尽量把显存用满,但留出10%给推理过程中的临时张量;max-model-len设32768是因为我们要把接口文档和设备信息一起塞进上下文,太短会截断。
注意:
max-model-len不是越大越好。它直接决定推理时的显存占用,设得过高会导致并发量上不去。先统计你实际要传入的最大文本长度,再加20%~30%的余量,是相对合理的做法。
本地部署还有一个容易忽略的点:模型加载后的第一次推理往往很慢,业界叫“冷启动”。要保证持续集成任务不被它拖垮,最好做一个常驻推理服务,并在服务启动后发一次预热请求。
2.4 商用API的接入技巧与成本控制
如果不涉及数据合规问题,商用API依然是效率最高的选择。我们早期就在API方式下快速验证了“提示词模板→用例生成→人工评审”的可行性。接入时有一个参数特別值得关注:temperature。
生成测试用例这个任务,需要的是稳定性和准确性,不是创造性。所以temperature要调低,我们一般设置在0.2以下。你肯定不想让模型每次都生成风格迥异的用例,那样后期维护成本很高。另外max_tokens要根据用例类型设一个合理上限,接口用例通常不会太长,设1024或2048就够,太长不仅浪费钱,还可能让模型胡编乱造。
成本控制上我们的经验是:不要每次生成都带上整份接口文档和全部业务背景,可以把常用上下文做成固定前缀缓存起来。在API层面,就是合理的system prompt设计,将稳定的背景信息放在前面,将每次变化的请求参数放在后面。这样既省Token,又能保证输出的稳定性。
3. 核心细节解析与实操要点
3.1 一次完整的“接口文档→测试用例”要经历什么
我拿一个典型的订单查询接口举例,说明整个生成过程。接口文档大概是这样的:
{ "name": "查询订单列表", "method": "GET", "path": "/api/order/list", "params": { "user_id": "string, 必填, 用户ID", "status": "string, 可选, 枚举值:pending/paid/shipped/completed/cancelled", "page": "integer, 可选, 默认1, 最小1", "page_size": "integer, 可选, 默认20, 最小1, 最大100" }, "response": { "code": "integer", "data": { "list": "array", "total": "integer" } } }我们把这段文档和相关业务备注一起发给模型,提示词里明确要求:
- 先按正常、边界、异常三类场景设计用例;
- 每个用例包含:用例名称、前置条件、请求参数、预期结果;
- 覆盖每个参数的枚举值和边界值;
- 考虑参数之间的组合关系。
模型输出我们稍作整理后,得到了下面这份用例集:
| 用例名称 | 前置条件 | 请求参数 | 预期结果 |
|---|---|---|---|
| 正常查询全部订单 | 用户已登录且有订单数据 | user_id=1001, page=1, page_size=20 | code=0, 返回订单列表 |
| 按状态筛选已支付订单 | 用户存在已支付订单 | user_id=1001, status=paid, page=1, page_size=20 | 列表只包含paid订单 |
| status传非法值 | - | user_id=1001, status=abc | 返回参数校验错误 |
| page为0 | - | user_id=1001, page=0, page_size=20 | 返回参数校验错误或自动修正为1 |
| page_size超出上限 | - | user_id=1001, page=1, page_size=101 | 返回参数校验错误 |
| 用户不存在 | user_id不存在 | user_id=999999, page=1, page_size=20 | 返回业务错误码或空列表 |
这份结果看起来并不惊艳,很多资深测试自己也能写出来。但关键在于生成时间:从请求发出到拿到完整用例集,大约只用了十几秒。同样的工作量,手工大概要十五分钟到半小时。前者适合作为初稿,再让测试工程师在上面补充业务特有的场景,效率提升明显。
3.2 提示词模板设计:这事没有想象中那么简单
提示词是整个方案里最值得花时间打磨的部分。我们迭代了七个版本,才形成一套相对稳定的模板。核心设计思路是“角色设定 + 任务分解 + 输出约束 + 参考范式”。
先说角色设定。我们会在提示词里告诉模型“你是一名有10年经验的测试架构师”,一开始我觉得这句话像玄学,但多轮对比后发现,角色设定确实能影响输出文本的风格和质量。加了角色设定后,模型更倾向于输出结构完整、考虑周全的用例,而不是简单罗列。
任务分解是最关键的部分。不要一上来就让模型“写测试用例”,而是分三步走:
- 第一步,让模型梳理被测需求中的功能点。列出“系统应该支持什么、不允许发生什么”。
- 第二步,针对每个功能点列出测试场景。区分正常流、备选流、异常流。
- 第三步,为每个场景补充具体用例数据和预期结果。
输出约束方面,明确要求用JSON格式返回,字段固定为name、precondition、request、expected。这样后期解析入库非常方便。从第四版开始,我们在提示词里加入了参考范式,就是给模型看一个手工写好的优秀用例,告诉它“请参考这个质量水平”。这个动作对输出质量的提升出乎意料地大。
下面是一个简化后的提示词模板,基本包含了我们沉淀下来的核心要素:
你是一位资深的测试架构师,擅长接口测试用例设计。 请根据以下接口文档,生成完整的接口测试用例。 接口文档: {document} 要求: 1. 先分析接口的功能点、参数约束、业务规则; 2. 分别设计正常场景、边界场景、异常场景的测试用例; 3. 每个用例包含字段:name, precondition, request, expected; 4. 覆盖每个参数的类型、边界、枚举值,以及参数之间的组合; 5. 用JSON数组格式返回,不要输出额外解释。 优秀用例参考: {example_case}3.3 生成结果如何校验:别让模型“一本正经地胡说八道”
大语言模型最让人头疼的问题就是幻觉。在我们这个场景里,幻觉主要表现为三类:
- 编造接口字段。文档里没有的字段,模型因为见过类似接口的写法,自动给你补上了。
- 编造业务规则。比如文档里没说过“未支付订单只能保留30分钟”,模型也会按照行业习惯加进去。
- 编造测试数据。生成一个不存在的用户ID、一个不符合规则的商品编码。
针对这些问题,我们的解决方案是“双层校验”。第一层是格式校验,用JSON Schema校验模型输出是否符合约定的结构。第二层是语义校验,把模型抽取到的接口字段、请求参数和原接口文档做比对,字段不在文档里的直接标红提醒。
注意:模型输出里的预期结果不要直接当真。我们在实践中发现,模型经常会把“应该返回200”写成“应该返回500”之类的低级错误。这一块最好交给测试人员做快速确认,或者配合接口定义里的响应码规范做自动修正。
3.4 让模型输出结构化数据:JSON是首选
我们要求模型输出JSON,而不是自然语言描述,原因很简单:后续要做用例入库、去重、自动执行,结构化数据是刚需。但模型输出JSON有一个经典问题——JSON格式不稳定,偶尔会在末尾多出解释性文字,或者字段名大小写不一致。
解决方案有两个。一是效验后重试:用JSON解析库解析失败时,把错误信息拼进提示词,让模型重新生成。实测下来,这个办法能解决大约一半的格式问题。二是约束解码:在vLLM这类推理框架里启用guided_json功能,从生成阶段就限制输出必须符合指定的JSON Schema,这个方案基本能彻底解决格式问题。
from openai import OpenAI client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY") resp = client.chat.completions.create( model="Qwen/Qwen2.5-Coder-14B-Instruct", response_format={"type": "json_object"}, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_content} ] )这串代码是我们在Python里调用本地推理服务的方式,兼容OpenAI接口格式。只要后端启用了guided_jon或者response_format约束,前端代码不需要做额外处理,模型输出就能稳定是JSON。
3.5 从单条生成到批量执行:Pipeline才是真正的落地形态
单次调用模型出用例其实很简单,难的是把它做成一个在每次迭代中自动运行的服务。我们最终的形态是一个流水线,分五个阶段:
准备阶段:自动从Git仓库拉取接口定义文件和需求文档。这一步是自动化的基础,如果文档不维护,后面全完蛋。
预处理阶段:把接口文档切分成适合模型上下文长度的片段。不是把所有接口一股脑塞给模型,而是按模块、按依赖关系分组,避免模型上下文过载。
生成阶段:按批次调用模型,每批处理一组相关接口,附带统一的系统提示词和团队沉淀的参考用例。
校验阶段:格式校验、字段比对、用例去重、人工抽检。这一阶段会拦截大量模型幻觉产物。
入库阶段:把校验通过的用例转为测试平台的标准格式,自动关联到对应接口上。
这套流水线跑通后,我们每周迭代的成本从“测试工程师花两天设计接口用例”降到了“AI生成+人工评审一小时左右”。数字背后更重要的变化是:人工从重复劳动里解放出来,能去关注真正需要经验判断的复杂场景。
4. 常见问题与排查技巧实录
4.1 模型生成的用例“太泛”,没有业务特色
这是接入手两周后我们最头疼的问题。模型生成的用例确实覆盖面广,但每个用例都是“请求发出去,然后看返回值”,完全没有业务判断力。比如订单超时关单这种场景,模型是想不到的。
后来我们发现,问题出在输入信息的缺失。我们只给了接口文档,没给业务规则说明,而接口文档是描述“接口长什么样”,不是描述“业务怎么运转”。改进方式是:在提示词中加入业务背景和典型异常场景描述。比如“该接口需要校验用户是否有权限查看他人订单”“当订单状态为已取消时,不允许再发起支付”,这些规则只要是团队里已有的业务沉淀,都可以喂给模型。
另一个有效手段是注入历史缺陷数据。我们在系统提示词里加入“以下是从缺陷库中抽取的历史问题类型,请在用例设计中重点回归这些场景”,模型的用例设计立刻就有了针对性。
4.2 同样的提示词,输出质量时好时坏
这种情况多半是采样参数没固定。我们在生产环境把temperature固定为0.1,top_p固定为0.9,输出稳定性明显提升。另外,如果你用的是本地部署的开源模型,不同版本的模型文件也会影响输出,升级版本后建议先跑一轮冒烟用例,对比输出质量再决定是否全量切换。
4.3 上下文太长,模型越到后面越“迷糊”
接口文档动辄几万Token,业务规则再一加,很容易超过模型的上下文窗口。这时候模型会表现出两种症状:要么忽略前面的指令,只根据后面的内容回答;要么直接截断,输出不完整。
我们的处理办法是“分段 + 摘要”。把大文档按接口模块切段,每个模块独立生成用例;同时把公共业务规则做成摘要,作为固定前缀注入每个段落的提示词里。这比一次性把所有内容都塞给模型要稳定得多。
4.4 怎么评估这套方案真的有效
最后说一个最容易被人忽略的问题:你怎么证明AI生成的用例比人工写得好?我们内部建立了一套评估指标:
- 用例对接口参数的覆盖率:统计所有参数是否都有合法、边界、非法三类用例。
- 用例去重率:AI生成的大量重复用例占比多少。
- 人工评审通过率:随机抽20%的生成结果给资深测试评审,标记可用的比例。
- 缺陷发现率:新生成的用例跑完一轮后,发现了多少存量测试没发现的缺陷。
其中“缺陷发现率”是最有说服力的指标。我们在一次电商订单模块的回归中,AI生成的用例发现了一个在极端组合参数下才会触发的金额计算错误。这个场景在原有测试设计里完全不存在。那一次之后,团队对AI生成用例的态度从怀疑转成了“真香”。
4.5 几个日常最容易忽略的小细节
最后分享几个实操层面的细节,每一条都是我们真实踩过的坑换来的:
第一,不要直接在生产环境用未经微调的通用模型做高度专业化领域的用例生成。通用模型对金融、医疗等特定领域的业务规则理解有限,先用提示词工程试跑,实在不行再考虑微调。微调的成本远比你想象得高,需要准备高质量的训练样本,并持续维护。
第二,模型生成用例后一定要做权限与风险自查。比如用例中包含的账号、手机号、身份证号不要用真实数据,要做脱敏处理。这是测试环境的安全红线,自动生成的代码和用例尤其容易忽略。
第三,定期更新模型版本。语言模型的能力迭代很快,我们每季度会做一次新模型版本的对比评估。每次升级前,用固定的评估集跑一遍,对比新旧版本在用例生成质量上的差异,再决定要不要切换。
第四,保留人工审核环节,至少在关键业务上保留。AI生成用例的定位是“初稿生成器”和“覆盖面补充器”,它不是替代测试工程师的思考,而是帮测试工程师省掉重复劳动的时间。我们最终的模式是“AI负责量大面广,人负责疑难杂症”,这也是目前性价比最高的搭配。
5. 从单点工具到平台能力的演进路径
5.1 第一阶段:独立脚本阶段
刚开始我们就写了一个简单的Python脚本,读取接口文档、调用模型、输出JSON文件。它解决了“有没有”的问题,但离“好不好用”差很远。这个阶段的局限在于:只有一名测试开发在本地跑脚本,结果无法共享,也没法跟测试平台打通。
5.2 第二阶段:服务化阶段
当团队里其他测试同事也想用时,我们把它封装成了一个内部服务。提供Web界面,测试人员可以上传接口文档、选择模板类型、点击生成。生成结果自动存入测试用例管理库。这个阶段的核心收获是:把“能力”变成了“服务”,团队协作的效率提升了很多。
5.3 第三阶段:流水线集成阶段
再往后,我们把它接入了持续集成流水线。每次代码合并后,自动检测接口定义是否有变更,有变更就自动触发用例生成和补充测试。这个阶段才真正实现了“让用例跟上代码迭代”的目标。代码变更了一个字段,测试用例马上就能补上对应的校验用例,再也不用等测试工程师忙完手头的活儿再去补用例了。
这条演进路径给我们最大的启示是:AI能力不是一次性接入就完事了,它需要跟现有工程体系深度耦合,才能把价值发挥到最大。单纯“用AI写几条用例”没有壁垒,真正的壁垒在于把AI嵌入到研发流程里,让它成为流程的一部分。
6. 写在最后:一个过来人的几句心里话
做了这大半年的实践,我最大的感受是:大语言模型生成测试用例这件事,技术本身不是瓶颈,真正的瓶颈在于组织的输入质量。如果你的接口文档常年不更新,需求描述含糊不清,那再强的模型也生成不出好用例。反过来,当你的文档、规则、历史数据都被整理得井井有条时,模型生成用例的质量会远远超出你的预期。
个人建议,可以考虑从一个小项目试点开始,找一个接口数量适中的模块,跑通“文档输入—模型生成—人工审核—入库执行”的最小闭环,再逐步扩展。不要一上来就想做一套完美的平台,那是一步一步长出来的。我们当初就是从一段几十行的脚本开始的,走到今天,它已经变成了团队日常开发流程里一个不起眼但离不开的齿轮。
如果让我只说一句经验,那就是:AI生成测试用例最大的价值不是“替代人”,而是“把人的时间还给真正需要思考的地方”。