用例写完就完事了?接口自动化才是省人的那一步

0 阅读6分钟

图片

测试人 Skill 全家桶 · 第③篇

前两篇,我们把需求拆成了测试点、又把测试点变成了可执行用例。 但用例再准,也得有人跑。这一篇讲:怎么把接口用例变成 pytest、断言怎么分四层、怎么接进 PR 门禁,让机器替你守。


一、先看一个你肯定经历过的场景

图片

【贴图 01】

版本要发,你手里 60 条接口用例。

  • 要么手工点:登录、拿 token、改参数、点发送、拿响应、肉眼比对……一轮下来半天没了,还点漏了两条;

  • 要么写了个脚本:地址硬编码、每次跑都往库里灌垃圾数据、换个环境全挂、只断言了个 status_code == 200。

上线后出了个接口 bug,你翻脚本才发现——它压根没校验业务码。200 是拿到了,code = 5001(参数非法)它也没管。

图片

【贴图 02】

问题不是"没写自动化",是写成了"能跑但没用"的自动化:跑得挺欢,一条真缺陷都拦不住。

一句话:

自动化不是"把点鼠标换成跑脚本",是"让机器替你守门"。

守不住门的脚本,只是把加班从手工搬到了改脚本。


二、接口自动化的四根柱子

图片

【贴图 03】

这个 Skill 把接口自动化拆成四根柱子,缺一根都会塌:

| 柱子 | 要解决的问题 | 反面 | | --- | --- | --- | | 契约 | 测什么、参数长啥样 | 靠记忆、靠口口相传 | | 断言分层 | 怎么判"过了" | 只断言 200 | | 数据 fixture | 数据从哪来、到哪去 | 硬编码、不回收 | | CI 分层 | 什么时候跑、谁挡门 | 全量每晚跑,门禁是空的 |


三、第一根柱子:契约先行,不靠记忆

图片

【贴图 04】

写接口用例第一步永远是:找到这份接口的契约——OpenAPI / 抓包 / 接口文档,三选一,并且写进用例注释里。

契约要拆出这些:method、path、headers、body schema、成功状态码、业务码。

为什么强调"契约来源"?因为 AI 会编参数。你让它写个接口用例,它可能顺手给你编一个 userId=123、token="Bearer xxx"——看着像真的,全是假的。给它契约,它才不猜。


四、第二根柱子:断言分四层(最容易被偷懒)

图片

【贴图 05】

只断言 status_code == 200,是接口自动化最大的谎言。

200 只说明"HTTP 通了",不代表"业务对了"。正确的断言要分四层,从外到内:

① HTTP 状态码   → r.status_code == 200
② 响应结构       → set(body) >= {"code", "data"}
③ 业务码         → body["code"] == 0
④ 关键字段值     → body["data"]["threshold"] == 10000

真实例子(优惠券查询接口 GET /coupon/available):

@pytest.mark.smoke
def test_coupon_available_ok(coupon_client, seed_user):
    r = coupon_client.get("/coupon/available", params={"userId": seed_user.id})
    assert r.status_code == 200                      # ① HTTP 层
    body = r.json()
    assert set(body) >= {"code", "data"}             # ② 结构层
    assert body["code"] == 0                         # ③ 业务码层
    assert body["data"]["threshold"] == 10000        # ④ 关键字段层(满 100 元)

图片

【贴图 06】

四层里,第 ③④ 层才是真正在测业务。前两层只是"门没塌",后两层才是"货对不对"。


五、第三根柱子:参数化 + fixture(数据要"来有影、去有踪")

图片

【贴图 07】

等价类和边界值,不要手抄 8 遍用例,用 @pytest.mark.parametrize:

@pytest.mark.regression
@pytest.mark.parametrize("amount,expect_code", [
    (9999,  0),      # 未满门槛:正常返回,无可用券
    (10000, 0),      # 恰好满门槛:边界
    (10001, 0),      # 超出门槛
    (-1,    4001),   # 非法金额:业务码报错
])
def test_coupon_threshold_boundary(coupon_client, seed_user, amount, expect_code):
    r = coupon_client.get("/coupon/available", params={"userId": seed_user.id, "amount": amount})
    assert r.json()["code"] == expect_code

数据从哪来?fixture 生成,自动回收:

@pytest.fixture
def seed_user(db):
    uid = db.create_user(balance=10000)
    yield uid
    db.delete_user(uid)      # 跑完必回收,不污染下游

两条铁律:不写死测试数据、跑完必须清理。否则你的自动化就是在给测试库倒垃圾。


六、第四根柱子:接进 CI,把门关上

图片

【贴图 08】

自动化不进 CI,等于白写。这个 Skill 给的是三层策略:

  • 标记分层

    :@pytest.mark.smoke(秒级,每次 PR) / @pytest.mark.regression(每晚);

  • 失败留证据

    :失败时打印 request / response,CI 里一看就知道哪层挂了;

  • 超时与重试

    :只对网络类错误重试,业务失败绝不重试(否则把真 bug 重试没了)。

一个最小门禁配置(GitHub Actions):

- name: 接口冒烟
  run: pytest -m smoke --maxfail=1 -q

图片

【贴图 09】

还有两个隐形的坑,一并堵上:token 复用(在 conftest 里登录一次,别每个用例都登)、环境地址走配置(读环境变量,别硬编码)。


七、同一个接口:裸问 vs 用 Skill

图片

【贴图 10】

拿 GET /coupon/available 当输入。

裸问 AI 给的(跑得欢,没用)

图片

def test_coupon():
    r = requests.get("http://test.xxx.com/api/coupon/available")
    assert r.status_code == 200

问题:地址硬编码、没鉴权、只断言 200、没参数化、不清理数据。

用「接口自动化 Skill」给的(节选)

图片

  • 契约解析 → 用例骨架(正向 / 边界 / 异常 / 权限)

  • @parametrize

     覆盖金额边界(9999 / 10000 / 10001 / -1)

  • 四层断言

    逐层校验

  • fixture

     造数 + yield 回收

  • token 在 conftest 复用

  • @pytest.mark.smoke / regression

     分层,接 PR 门禁

同一件事,前者是"能跑",后者是"能守门"。


八、这个 Skill 长什么样

工作流程(6 步):

① 契约解析:method/path/headers/body/状态码/业务码
② 用例骨架:正向 + 边界 + 异常 + 权限
③ 参数化:parametrize 覆盖等价类与边界
④ 断言分层:状态码 → 结构 → 业务码 → 关键字段值
⑤ fixture:数据准备 + 自动回收(yield)
⑥ CI 接入:标记分层 / 失败重试 / 报告留档

检查清单(核心资产):

· 一个接口一份契约来源,不靠记忆
· 断言分 4 层,至少覆盖「业务码 + 关键字段」
· 测试数据由 fixture 生成并回收
· token 复用,不每个用例登录一次
· 失败时打印 request / response(可定位)
· 用例幂等,可重复执行
· 打标记:@pytest.mark.smoke / regression
· 超时与重试策略明确(只重试网络类错误)
· 环境地址走配置,不硬编码

硬性规则:不写死测试数据 / 不在用例里写业务判断(逻辑走断言)/ 每次跑完必清理 / 断言必须含业务码或关键字段。

反模式:❌ 只断言 status_code == 200 ❌ 用 sleep 等异步结果 ❌ 用例依赖执行顺序 ❌ 地址账号写死。


九、落地效果 + 踩过的坑

效果(团队自测,仅供参考):

  • 冒烟用例进 PR 门禁:8 分钟内给出结果,坏改动挡在合并前;

  • 接口回归:约 1.5 天 → 约 40 分钟(参数化 + 分层,不用全量跑);

  • 接口层漏测缺陷:显著下降(业务码层断言立了大功)。

四个坑(一定要看):

  1. AI 爱只断言 200

    ——必须显式要求"断言分四层,业务码必检";

  2. AI 爱用 sleep 等异步

    ——改成轮询 + 超时上限,或让接口提供回调/查询;

  3. 数据不回收 → 污染下游

    ——fixture 一律 yield + 清理,宁可多写两行;

  4. 重试滥用

    ——只重试网络类错误;业务失败重试,等于把真缺陷藏起来。


🎁 彩蛋公众号后台回复「skills」,领取《测试人 Skill 全家桶》:本文 api-automation SKILL.md 完整版 + 10 个 Skill + 适配手册。 👉

下篇预告:《UI 自动化总在"等元素",到底该等多久?》—— 接口稳了,UI 层才是真磨人。下一篇讲:Playwright 怎么写稳、定位为什么优先 data-testid、以及"自愈"到底能救回多少条。