87个接口,手工点测3天,AI跑完3小时——核心不是模型多强,是Swagger够干净
大家好,我是某互联网公司的测试架构师。
上个月,团队接了一个订单中台的回归测试。87个接口,前后端分离,Swagger文档写得整整齐齐。测试组长看了一眼排期,说了一句:“按老规矩,3天起步。”
他说的“老规矩”,是用Postman手工点测。87个接口,每个接口测正常流、缺参、类型错、边界值、鉴权,一个接口平均6-8条用例,加起来500多条。一个人点一遍,3天是乐观估计。
我说:“你让我用AI跑一遍试试。”
3小时后,CI上跑了529条pytest用例,全量回归通过。MR冒烟测试只要20分钟。
测试组长看完报告问了一句:“你怎么做到的?”
一、先别碰AI——把Swagger弄干净
这是整个流程里最容易被跳过、也最重要的一步。
我一开始也想着直接把Swagger文件喂给大模型,让它生成用例。结果AI生成了一堆不存在的字段——它把orderStatus写成了order_state,把amount的枚举值猜成了字符串数组。
后来我发现,问题不在AI,在Swagger本身。
我们要求每个接口必须满足五个条件:
OpenAPI 3.0,别拿Swagger 2.0凑合
operationId唯一,后面用例ID靠它
每个schema字段尽量有example
必填字段、枚举、最大最小长度写清楚
错误响应别只写个400,把业务错误码也列出来
校验命令放在pre-commit里:
openapi-spec-validator openapi.yaml
这一步很枯燥,但省不掉。Swagger越像合同,后面生成的用例越像回事。
二、把接口抽成“用例原材料”
Swagger清洗干净了,下一步不是直接生成测试文件,而是先生成一份可人工审核的YAML。
我写了一个脚本,把OpenAPI里的operation拉平:
tools/extract_ops.py
import yaml
HTTP_METHODS = {"get", "post", "put", "patch", "delete"}
def extract_operations(spec):
for path, methods in spec["paths"].items():
for method, op in methods.items():
if method notin HTTPMETHODS:
continue
yield {
"id": op.get("operationId") orf"{method}{path}".replace("/", "_"),
"method": method.upper(),
"path": path,
"summary": op.get("summary", ""),
"parameters": op.get("parameters", []),
"requestBody": op.get("requestBody", {}),
"responses": op.get("responses", {}),
}
if name == "main":
with open("openapi.yaml", encoding="utf-8") as f:
spec = yaml.safe_load(f)
ops = list(extract_operations(spec))
with open("cases/raw_ops.yaml", "w", encoding="utf-8") as f:
yaml.safe_dump(ops, f, allow_unicode=True, sort_keys=False)
print(f"抽到 {len(ops)} 个 operation")
87个接口,抽出来87条operation。但这只是原材料,不是用例。
三、让AI干它擅长的:想场景
接口测试最烦的不是发请求,是想“还要测什么”。正常流谁都会写,缺参、类型错、边界值、权限、幂等——这些才费脑子。
我把每个operation的JSON发给模型,要求只输出JSON,不要解释:
你是一个接口测试专家。下面是一个OpenAPI operation的JSON。
请生成pytest参数化用例,输出JSON数组,每个元素包含:
{
"id": "唯一ID",
"name": "用例名",
"path_params": {},
"query_params": {},
"headers": {},
"body": {},
"expected_status": 200,
"expected_assertions": []
}
覆盖场景:正常流、缺参、类型错、边界值、权限异常。
实测效果:87个operation,AI生成了529条用例。平均每个接口6条——正好覆盖正常流、缺参、类型错、边界值、鉴权和幂等。
但AI生成的用例不能直接用。我让同事花了两小时做了一轮审核,主要检查三件事:
第一,断言写得太弱。 AI生成的断言往往是assert response.status_code == 200,只校验状态码。我要求改成assert data["code"] == 0 and data["data"]["orderId"] is not None。
第二,依赖关系没处理。 比如“取消订单”用例需要先有一个已支付的订单。AI不知道这个依赖,生成的用例直接调取消接口,必然404。
第三,业务规则缺失。 比如“已发货订单不能取消”——这条规则只存在于产品经理的脑子里,Swagger里没有。AI不知道,生成的用例就没覆盖。
AI负责把场景“想全”,人负责把断言“写对”。
四、用pytest动态执行
AI生成的JSON用例,不直接转成.py文件,而是用参数化的方式动态执行:
import pytest
import yaml
import requests
with open("cases/ai_cases.yaml") as f:
ALL_CASES = yaml.safe_load(f)
@pytest.mark.parametrize("case", ALL_CASES)
def test_api(case, base_url, auth_token):
url = base_url + case["path"]
headers = {"Authorization": f"Bearer {auth_token}"}
resp = requests.request(
method=case["method"],
url=url,
params=case.get("query_params"),
json=case.get("body"),
headers=headers,
)
assert resp.status_code == case["expected_status"], (
f"用例 {case['id']} 状态码不匹配"
)
for assertion in case["expected_assertions"]:
# 简化示例,实际用jsonpath或schema校验
assert assertion["key"] in resp.json()
为什么用参数化而不是生成静态文件?
因为Swagger在变,AI生成的用例也在变。参数化让用例和代码解耦——Swagger更新了,重新跑一遍AI生成流程,用例自动更新,不用改一行测试代码。
五、效果:3天到3小时
最终数据:
指标
手工Postman
AI+pytest
接口数
87
87
用例数
手工写500+
AI生成529条
全量回归
3天
3小时
MR冒烟
半天
20分钟
用例维护
手动改
Swagger更新后自动重生成
人工投入
3天/轮
2小时审核 + 全自动执行
最关键的变化不是“快了”,是“可以持续跑” 。以前手工点测,一个月跑一次就不错了。现在CI上每天跑,每次MR自动触发。
有团队在支付平台API测试中做了类似的尝试:Agent基于Swagger生成1200+用例,用例生成时间从3天缩短到2小时,效率提升97%。跨境支付汇率计算场景,资深工程师要琢磨2天的边界组合,AI用15分钟生成了27种参数组合的用例集。
六、踩过的坑
坑一:Swagger不干净,AI就编。
我一开始直接拿Swagger 2.0的文档喂模型,AI生成了大量不存在的字段。Swagger必须是OpenAPI 3.0,operationId唯一,必填和枚举写清楚。
坑二:只让AI“生成”,不让AI“想”。
如果你只说“生成测试用例”,AI会给你一堆assert 200的弱断言。你必须明确要求它覆盖正常流、缺参、类型错、边界值、权限、幂等六类场景。
坑三:依赖关系没处理。
“取消订单”依赖“已支付订单”,“退款”依赖“已支付订单”。AI不知道这些依赖,你需要给它一个依赖链的上下文,或者用Skills把依赖处理拆成独立步骤。
坑四:生成完不审核直接用。
AI生成的529条用例里,有大概60-80条需要人工修正。断言写弱了、业务规则漏了、依赖没配。审核2小时,比从零写500条用例省下来的时间不是一星半点,但审核这一步不能省。
最后
AI+Swagger的核心,不是“让AI写用例”,是“把Swagger变成可执行的测试契约”。
Swagger写清楚了接口的“是什么”——路径、参数、类型、响应。AI补上了“还要测什么”——缺参、边界、鉴权、幂等。pytest负责“怎么跑”——参数化、断言、报告。
你不需要再手写500条用例了。你只需要把Swagger弄干净,让AI补场景,让pytest去干重复劳动。
下次你面对一个几百个接口的项目,别打开Postman了。打开Swagger文件,跑一遍清洗脚本,把operation丢给AI,说一句:
“帮我生成pytest参数化用例,覆盖正常流、缺参、类型错、边界值、权限和幂等。”
3小时后,CI上会跑完500多条用例。