ARTICLE · 1071279
从接口文档到测试用例:真正卡住你的不是提示词
多改几轮提示词就好了?
把文档里的约束
一条条圈出来
五步流程 · 四张清单 · 六种策略
测试不加班
📦 7 Parts + Conclusion
👉 滑动
PART 01
先看全貌
五步流程
PART 02
分清文档
三问归类
PART 03
圈出约束
四张清单
PART 04
策略铺开
四个点
PART 05
标优先级
两个字段
PART 06
自检六问
让缺口显形
PART 07
固化流程
三层解耦
PART ///
结语
先干一件更笨的事
有一类活,测试同学每周都在干:拿到一份需求文档或者接口文档,把它变成一套能执行的测试用例。
这两年大家习惯把它交给 AI 试试。流程通常是:把文档粘进对话框,敲一句“请根据这份文档生成测试用例”,然后看输出。看完的普遍感受是——东西是出来了,但不敢用。要么关键异常全漏了,要么塞了一堆凑数用例,要么格式跟团队的用例模板对不上。
于是很多人回头去改提示词。写得更长、更细,加角色设定、加输出格式要求、加一句“必须覆盖边界值和异常场景”。
改几轮就会发现
提示词不是瓶颈
瓶颈在前面那一步——你有没有把文档里的约束,一条不落地提出来。文档里写着“不超过 50 次”“只能是数字、大小写字母 _-|*@”“6qps”,这些不是背景介绍,每一条都是一个用例入口。你提不出来,AI 就没法替你铺开;你提出来了,后面的活儿确实可以交出去。
这篇文章不讲大道理,直接走一遍。演示素材用一份真实公开的接口文档:微信支付的「申请退款」接口(服务商模式的文档)。选它不是因为它是支付,而是因为它约束足够密——字段长度、字符集、业务规则、状态机、错误码、限流,五类约束齐全,正好用来当标本。
(本文仅作技术分析,与腾讯及微信支付官方无关联。)
下面是从文档到用例的完整五步。
01
PART
先看全貌:从文档到用例,中间是五步
OVERVIEW · 五步流程
先把流程摆出来,后面再一步步拆。

— 从文档到用例的五个步骤:判断文档类型、圈出全部约束、固定策略铺开、标类型优先级、自检六问
这五步里,第一、二步是人的活,也是最容易被跳过的地方;第三步是 AI 最擅长、能被放大的部分;第四、五步是兜底。
多数人把文档丢给 AI 的时候,直接跳到了第三步——这一步当然会失败。因为 AI 拿到的文本里,约束散落在七个业务规则、二十多个字段、十多个错误码里,它得先替你做完第二步才能开始第三步,而这个动作你从没让它做过,也没告诉它要做。
下面逐步来。
02
PART
第一步:先分清你手上是哪一类文档
STEP 01 · 文档归类
同样是“文档”,里面的东西完全不是一回事。先做归类,因为文档类型决定了后面叠加哪套覆盖维度。
拿这次的退款接口文档举例。它表面上是一份接口契约——有请求方式、有路径、有参数表、有错误码。但它里面还夹着一层东西:
申请退款总金额不能超过订单金额。一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号。
错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过 6 次。
这几句不是接口参数,是业务规则。它们决定了接口在什么情况下会被拒绝,属于典型的“功能需求”内容。如果只按接口文档的套路去覆盖(参数、错误码、鉴权),这几条会被完整地漏掉。
再看一段:
申请退款接口的返回仅代表业务的受理情况,具体退款是否成功,需要通过退款查询接口获取结果。
这一句是状态相关的说明,它直接决定了“这个接口能不能当作结果判定的依据”。这句话漏了,你后面所有涉及退款的用例预期都是错的。
所以归类不止一层,我习惯分成三问:
这份文档的归类结论就是:接口契约为主,混入业务规则与状态说明,存在查单接口和回调通知两个外部依赖。
一句话结论,但它决定了后面四张清单里要放什么。
这一步别省。省掉的后果是:你按接口文档的套路出了两百条用例,结果漏掉了“退款总金额不能超原订单”“部分退款不超 50 次”这两条业务红线——而这两条恰恰是最容易出生产事故的地方。
03
PART
第二步:把文档圈成四张约束清单
STEP 02 · 四张清单
这是全文最核心的一步,也是最枯燥的一步。
做法很简单:通读文档,只做一件事——把所有带约束力的句子划出来,然后归类。先别想着写用例,写用例是下一步的事。这一步的目标是把约束提干净。
我习惯分四类:格式、业务、状态、异常。
3.1 格式约束:字段层面的硬边界
格式约束藏在参数表里,标志词是“必填/选填”、类型标注 string(32)、以及“只能是……”。
从文档的请求参数表里,能提出这些(先说明一下:这份是服务商模式的文档,表格第一行的 sub_mchid 是服务商模式下才有的必填字段,非该模式的读者不用被它带偏):
| sub_mchid | ||
| transaction_id | ||
| out_trade_no | ||
| out_refund_no | ||
| reason | ||
| notify_url | ||
| amount.refund | ||
| amount.total | ||
| amount.currency | ||
| goods_detail[].merchant_goods_id |
这张表的价值在于:每一行都是一类用例的入口,而不是一行“已知信息”。
举两个容易漏的点。
第一个,notify_url 里那句“不能携带参数”。这句话的信息量很大——它意味着 https://a.com/cb?order=1 这种写法是非法的。如果你只覆盖了“必填/可选”,这条会漏。而回调地址带参数是很多人写代码时的习惯动作,正是需要用例拦住的。
第二个,amount.currency 写的是“符合 ISO 4217 标准的三位字母代码,目前只支持人民币:CNY”。这里有两层:格式上是三位字母,能力上只支持 CNY。所以 USD、JPY 属于格式合法但业务不支持——它和 cny(小写)、CN(两位)不是同一类失败,预期错误码可能也不同。这种“格式合法但业务不支持”的取值,是最容易被漏掉的中间地带。
3.2 业务约束:规则层面的数量与关系
业务约束的标志词是数字、次数、时间、金额关系。它们通常不在参数表里,而写在文档开头的“注意”段落中。
这份文档的注意段落一共七条,逐条登记:
这张表里有三个点值得单独拎出来说。
第一,“不超过 50 次”和“退款总金额不超过订单金额”是两条独立红线。很多人会合并成一条“部分退款有限制”。但它们约束的是不同维度:一次限制次数,一次限制金额。可能出现次数没超但金额超了,也可能金额没超但次数到顶了,用例必须分开设计。
第二,“一笔退款失败后重新提交,请不要更换退款单号”这句话,是一条幂等约定。它和另一句“同一退款单号多次请求只退一笔”要连起来看——前者说失败重试必须用原单号,后者说同单号重复请求只生效一次。这两句合在一起,才构成完整的重试语义。只看其中一句,你设计不出“失败→原单号重试→仍只退一笔”这条关键用例。
第三,限流有两个不同阈值:默认 6qps,一个月以上的订单 5000/min。这是一个按订单年龄分段的规则,所以“一个月”这个时间分界点本身就是一个边界。而且 6qps 限制的是“异常或错误的退款申请请求”——注意它限的是错误请求,不是全部请求。这个限定条件很容易读漏,读漏了用例方向就反了。
3.3 状态约束:进度层面的迁移
退款接口的应答里有一个 status 字段,取值是:
SUCCESS:退款成功 / CLOSED:退款关闭 / PROCESSING:退款处理中 / ABNORMAL:退款异常
四个状态里有一个是中间态(PROCESSING),两个是终态(SUCCESS、CLOSED),一个是异常终态(ABNORMAL)。而文档还有一句关键说明:
申请退款接口的返回仅代表业务的受理情况,具体退款是否成功,需要通过退款查询接口获取结果。
把这两条合起来,状态约束就清楚了:调用退款接口成功返回,不等于退款成功。返回 PROCESSING 只是一个中间态。
这一条决定了后续两类用例:
一是状态迁移用例——PROCESSING 之后走向 SUCCESS、走向 ABNORMAL、长时间停留不迁移。
二是判定依据用例——哪些场景下不能拿退款接口的同步响应当作结果,必须去调查询接口。
还有一条藏在错误码里:
ABNORMAL:退款异常——退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。
这句话的测试含义是:ABNORMAL 是一个需要人工介入的终态,不是自动重试的中间态。用例应该覆盖“进入 ABNORMAL 后的系统行为”,而不是“重试直到成功”。
3.4 异常约束:错误码层面的反向覆盖
最后一张清单,来自文档末尾的错误码表。公共错误码 4 个,业务错误码 10 个。
这张表有两个用法。
第一个用法很机械:每个错误码至少一条用例。这是接口测试的基本盘,不值得多说。
第二个用法才是关键:错误码表是逆向校验清单。你做完前面三张清单,回头对照错误码表——如果某个错误码你找不到触发它的用例,说明前面有约束你漏了。
举个具体例子。403 NOT_ENOUGH(余额不足)这个错误码,在参数表和业务规则里都找不到对应约束,只有错误码表里写着。它对应的场景是:商户账户余额不足以完成本次退款。这个场景在文档正文里没有正面描述,你只能从错误码反推。如果只读正文不读错误码表,这类场景会整块缺失。
再举一个。429 FREQUENCY_LIMITED 的解决方案里写着“请调用查单接口确认或降低频率原单重试,重试请勿更换单号”——这是一份接口级的错误处理约定。它不只是“测到限流就算完”,还要验证调用方是否按约定处理。这类用例往往跨了系统边界,属于最容易漏的一层。
到这里,四张清单齐了。回头看一下它们的来源:

— 四张约束清单的来源:参数表出格式约束,注意段落出业务约束,状态说明出状态约束,错误码表出异常约束
四张清单出来之后,其实用例的骨架已经有了。第三步只是把骨架填成肉。
04
PART
第三步:六种策略铺开,挑四个点完整走一遍
STEP 03 · 策略铺开
约束清单是“要覆盖什么”,策略是“用什么方法铺开”。常用的六种:
正向反向 / 异常边界值等价类状态迁移场景法
完整铺一份出来会很长,我挑四个信息量最大的点走一遍。每个点都按同一个格式:文档原文 → 约束分析 → 用例设计。
4.1 金额:一个 refund 字段,能挖出八条用例
amount.refund 必填 integer【退款金额】退款金额,单位为分,只能为整数,不能超过原订单支付金额。
申请退款总金额不能超过订单金额。
两句话里有三个独立约束:必须是整数、不能为负、单次和累计都不能超过原订单金额。
假设一笔原订单支付金额为 10000 分(100 元),设计如下:
| refund=10000 | |||
| refund=1 | |||
| refund=0 | |||
| refund=-1 | |||
| refund=10001 | |||
| refund=100.5 | |||

— 一个 refund 字段展开出 8 条用例
这里有几个设计细节值得说。
AMT-03 的预期我写的是“拒绝”,没写具体错误码。因为文档里没写 0 元退款会返回哪个错误码。这是一个文档缺口——准确做法是标记出来,找开发或产品确认,而不是自己猜一个填上。用例里写个猜的错误码,比留空更危险。
AMT-07 和 AMT-08 是一对,必须成对设计。只测“刚好等于”是正向验证,只测“超出”是反向验证,两个一起才是完整的边界。而且这对用例依赖前一次退款成功——这是典型的有状态用例,前置条件必须写清楚,否则执行人跑不出来。
AMT-06 容易被当成“参数类型错误”一笔带过。但支付场景里金额单位是分,前端如果传了元的数值(100.5),单位差 100 倍。这不是格式问题,是量纲问题。用例标题应该写清楚,别让它混在普通参数校验里。
4.2 两个订单号二选一:等价类加组合
transaction_id 选填 string(32)【微信支付订单号】原支付交易对应的微信订单号,与 out_trade_no 二选一。
out_trade_no 选填 string(32)【商户订单号】原支付交易对应的商户订单号,与 transaction_id 二选一。
“二选一”是接口文档里最常见的约束表述,也是最容易测不全的一种。它本质是两个字段的取值组合,所以要用等价类加组合覆盖。
两个字段各有“传/不传”两种状态,理论组合四种:
ID-03 是重点。“二选一”在中文里其实是有歧义的——它可以读作“必须选一个”(至少一个),也可以读作“只能选一个”(恰好一个)。两种读法对应的预期结果完全不同。
文档只写了“与 xx 二选一”,没有明说两个都传会怎么样。这就是一个需要澄清的缺口。
我处理这类歧义的做法是:用例照写,预期栏标注“待确认”,并在用例备注里写明两种可能和对应的验证方式。不要替开发做决定,也不要因为不确定就不写——写下来,评审时一次性问清楚。
ID-01 和 ID-02 还要注意一点:它们虽然都是正向用例,但底层实现路径可能不同——一个按微信订单号查,一个按商户订单号查,索引不同、边界不同。所以两条都要留,不能合并成一条“传订单号即可”。
4.3 退款单号:幂等到底怎么测
这是这份文档里信息密度最高的一组约束。
out_refund_no 必填 string(64)【商户退款单号】商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母 _-|*@ ,同一退款单号多次请求只退一笔。
一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号。
关键返回值:refund_id【微信支付退款号】、out_refund_no【商户退款单号】。
把这几句连起来,幂等语义是:
同一 out_refund_no 多次请求 → 只退一笔。这是服务端的幂等保证。
退款失败后重试,必须沿用原 out_refund_no。这是调用方的义务。
这两句话,一条约束服务端,一条约束调用方,测的对象完全不同。很多人只测了前者(重复提交不重复退款),漏了后者(调用方是否守约)。
围绕这一点,设计六条用例:
IDM-02 是这组里最有价值的一条。它的现实来源是:同一个退款单号在不同业务分支里被复用了,但金额取的是最新计算值。这类问题不会在“参数校验”层面暴露,只有靠幂等场景才拦得住。
IDM-04 值得单独说。文档说“请不要更换退款单号”,但没有写换单号会怎样。所以这条用例的预期栏必须留空或标“待确认”。它的价值不在于验证某个已知结论,而在于把文档里的空白点变成一个显式的验证动作。
顺带说一个和幂等强相关的字段:out_refund_no 的字符集是“数字、大小写字母 _-|*@”。注意这里面有 |、*、@ 三个特殊字符,却没有常见的 .、#、/。这类白名单型约束,边界用例要正反都测:白名单内的每个特殊字符各来一条(至少抽 2~3 个),白名单外挑 1~2 个做反向。同时要测边界长度——64 位整好,65 位拒绝。
4.4 50 次和 6qps:次数与频率的边界
最后这组是数量型约束,边界值策略的主场。
次数上限:
CNT-02 和 CNT-03 是一对边界。这里有个执行成本问题必须提醒:要跑到第 51 次,前置数据得先构造出 50 次退款记录。这条用例不能靠手工点,通常得写脚本刷数据,或者在测试环境直接改库构造。用例里要把这个前置条件写明白,不然执行人会卡住。
频率上限:
QPS-01 和 QPS-02 的边界设置,依据是文档那句“错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过 6 次”。
注意这里的措辞——限的是“异常或错误的退款申请请求”。所以 QPS-01/QPS-02 的输入必须是错误请求,用正常请求去测,方向就错了。这类细节不看原文是想不到的。
QPS-04 里的“31 天”是我为“一个月之前的订单”选的一个取值。文档说的是“一个月”,没有给精确天数,所以用例里还应该补一条分界点用例:第 30 天和第 31 天分别测,把“一个月”这个模糊表述逼成一个可验证的边界。
05
PART
第四步:标类型和优先级
STEP 04 · 类型与优先级
用例铺完了,但还不能交出去。缺两个字段:类型和优先级。
类型是给后面做自动化选型用的。这一步的判定标准其实很清楚——能不能被程序稳定判定:
优先级我按这个口径分:
优先级怎么定的?我的口径是:P0 只放两件事——钱算错、钱多退。AMT-08(累计超额)和多退一笔,都属于直接资损,必须 P0。而像 reason 字段超 80 位这种,出错只是少了个退款原因,不影响资金,P2 足够。
别把所有正向用例都标 P0。全 P0 等于没有优先级。
06
PART
第五步:自检六问
STEP 05 · 自检六问
出完用例,回头过一遍这六个问题。这一步不用 AI,用眼睛看更快。
自检里发现了两处缺口,都真实存在:
一是 status 的四个取值里,CLOSED(退款关闭)什么情况下会进入,文档没写清楚。需要补充澄清。
二是 funds_account(退款资金来源)这个字段,可选值只列了 AVAILABLE(仅对老资金流商户适用),新资金流商户这个字段该怎么传,文档没说明。这类字段往往被当成“用不到”跳过,但一旦上线遇到老商户,就会露出问题。
这两处都留在清单里,标注“待确认”——自检的价值不是让清单好看,而是让缺口显形。
07
PART
顺带说说:这套流程怎么固化下来
HOW TO · 固化与解耦
走完一遍,你会发现两件事。
第一,五步里真正耗时的是第二步。圈约束那一步占掉了整个流程里最多的时间,而且它没有捷径——文档写的东西你只能一句句读。这也是为什么“把文档丢给 AI 直接出用例”总是不理想:你跳过的那一步,恰恰是最重的那一步。
第二,这套流程里有一大半是可以固化的。第三步的铺开策略、第四步的类型与优先级口径、第五步的自检清单——这三步的规则是稳定的,跟具体文档无关。
所以自然的想法是把它们做成一个可复用的 Skill,下次直接把文档丢进去。
我读到过一套第三方公开分享的测试用例生成 Skill 实现(doc-based-testcase-generator),它与我没有隶属或商业关系,这里只借它的分层方式做方法论对照:把通用设计策略(正向、反向、边界值、等价类、状态与流程、场景法)单独放在主体说明里,把各类型的专用标准(接口、功能、性能、自动化)拆成若干份参考文档按需加载,再用一个独立的目录存放团队的 Word/Excel 模板来对齐输出格式。
这个拆法最聪明的地方是解耦:
策略和标准分开
策略回答“用什么方法想”,标准回答“某一类要覆盖哪些维度”。混在一起写,改一处就牵动全身。
输出格式外置
不写死表格列名,把列名交给团队模板。因为每个团队的用例模板都不一样,写死了就没法复用。
我自己的做法和它思路一致,差别在于:我把第二步(圈约束)单独做成了一个强制环节,要求先产出四张约束清单,再进入生成。上面那套公开实现里也有对应动作——它会先解析文档类型、提取模块与约束清单,再做设计,最后用一份自检问题过一遍。
区别在哪?它把“提取约束”作为内在步骤,我把它做成了显式的检查点——清单必须落成表,摆出来看一眼。
这个差别不是形式主义。隐式步骤会被跳过,显式清单不会。当 AI 自己完成提取时,你无法判断它提全了没有;当它必须把清单输出给你时,漏了哪条你一眼就能看见。
如果只让我从这套流程里保留一个动作,我保留第二步。
隐式步骤会被跳过,显式清单不会
///
LAST
结语
CONCLUSION · 一句话
回到开头那个问题。为什么提示词改了那么多轮,输出还是不敢用?
因为你在优化的,是整套流程里最靠后的那一步。真正决定用例质量的,是文档里的约束有没有被提干净。这一步现在还没有省事的办法——它得靠你一句句读原文,把每个“必填”“不超过”“不能携带参数”都圈出来。
好消息是,圈完之后,剩下的活儿确实可以交出去。
所以下次拿到文档,别急着打开对话框。先干一件更笨的事:把文档里所有带约束力的句子划线、归类、列成表。表列出来那一刻,你会发现问题已经解决了一半——包括那些文档自己都没说清楚的地方。
既然看到这里了,如果觉得有用,随手点个赞、在看、转发三连吧。
THANKS FOR READING
#软件测试 #应届生求职 #自学软件测试 #计算机专业 #软件测试学习 #skill #ai生成测试用例 #ai测试 #ai工具 #ai测试学习