接口测试文档手册 · 通用篇
普通接口测试流程 + 实战方法 · 从看文档、写用例、调工具,到输出报告,按老师授课顺序讲清楚
这篇适合怎么学
如果基础篇解决的是"知道接口测试是什么",这一篇解决的是"拿到一个真实接口之后,到底先做什么、再做什么、最后怎么落报告"。建议跟着章节顺序边看边练。
步骤1:读需求和接口文档
💡 先别急着发请求
很多接口测试失效,不是因为不会用 Postman,而是因为一开始就没把业务规则读明白。
1.1 先读哪三样东西
- **产品需求:**业务到底想解决什么问题,成功标准是什么
- **接口文档:**请求、响应、错误码、鉴权、示例
- **历史问题:**这个模块以前炸过什么,最容易回归什么
1.2 文档评审时重点看什么
| 文档项 | 需要确认的问题 |
|---|---|
| 接口路径和方法 | 语义是否清晰,版本号是否明确 |
| 参数定义 | 哪些必填,哪些可选,默认值是什么 |
| 字段约束 | 类型、长度、枚举范围、精度、格式 |
| 错误码 | 哪些业务失败场景会返回什么码 |
| 权限说明 | 谁能调,谁不能调,跨角色行为是否不同 |
| 副作用 | 会不会落库、发 MQ、发短信、触发第三方 |
1.3 实战:三分钟读懂一份接口文档
示例
假设你拿到下面这段接口定义:
POST /api/orders
入参:
sku_id: string, 必填
count: int, 必填, 1~99
coupon_id: string, 可选
address_id: long, 必填
返回:
code=0 表示成功
data.order_id
data.status=PENDING_PAY
说明:
需要登录
库存不足时下单失败
支持幂等作为测试,你应该立刻想到这些问题:
- 登录是用什么 token 还是 cookie。
count的边界值是 0、1、99、100。coupon_id可选,那么不传时价格怎么算。- 库存不足时返回什么业务码,HTTP 状态码是多少。
- 支持幂等,具体用什么机制,是业务单号还是
Idempotency-Key。 - 下单成功之后有哪些副作用,例如扣库存、写订单表、发消息。 这就是"读文档即拆测试点"。不是把文档看完,而是把问题看出来。
1.4 文档里最常见的坑
文档不完整的高频表现
- 只写了成功示例,没有写失败场景
- 只写了字段名,没有写字段含义和约束
- 没有说明状态流转条件
- 接口行为变了,但文档没更新
- 对第三方回调、重试、幂等没有任何说明
步骤2:识别核心场景和依赖
接口测试不是把所有接口平均测一遍,而是先找到核心场景、关键链路、关键依赖。
2.1 用"用户旅程"找核心接口
注册 → 登录 → 浏览商品 → 下单 → 支付
把一条完整业务链路拆开,标出每个接口的优先级。通常影响交易、资产、身份、权限的接口都应是 P0。
2.2 画清楚接口依赖关系
示例
下单接口经常依赖这些模块:
- 用户服务:校验用户状态和收货地址
- 商品服务:获取商品价格和 SKU 信息
- 库存服务:预占库存
- 营销服务:计算优惠券和活动价格
- 支付服务:生成待支付单 所以你测
POST /api/orders,本质是在测一条跨多个系统的链路,不是一个孤零零的接口。
2.3 场景优先级怎么排
| 优先级 | 适合哪些接口 | 建议策略 |
|---|---|---|
| P0 | 登录、下单、支付、退款、权限校验 | 必须全量覆盖正常 + 异常 + 权限 + 并发 |
| P1 | 列表查询、详情查询、配置接口 | 覆盖主流程和主要边界 |
| P2 | 统计、辅助类、低频后台接口 | 抽样覆盖,放入回归集 |
步骤3:拆测试点
3.1 接口测试点的六层拆法
| 层次 | 关注问题 | 例子 |
|---|---|---|
| 协议层 | 方法、路径、header、Content-Type 对不对 | 上传接口却传了错误 Content-Type |
| 参数层 | 必填、类型、长度、格式、枚举 | 手机号长度不足 11 位 |
| 业务层 | 规则是否生效 | 库存不足不能创建订单 |
| 状态层 | 前后状态是否合法 | 已取消订单不能支付 |
| 副作用层 | 落库、缓存、消息、第三方调用是否正确 | 下单后是否真的扣减库存 |
| 安全层 | 鉴权、越权、敏感信息、签名是否正确 | 普通用户不能查管理员数据 |
3.2 一个通用的拆点模板
1. 正常输入能否成功
2. 必填缺失会怎样
3. 非法类型 / 非法格式会怎样
4. 边界值会怎样
5. 业务前置条件不满足会怎样
6. 重复请求 / 并发请求会怎样
7. 不同身份调用会怎样
8. 依赖服务失败会怎样
9. 返回结构和落库是否一致
10. 日志 / 链路 / request_id 是否可追踪3.3 别只拆输入,还要拆输出和副作用
常见漏测点
很多人把 90% 的精力都放在输入参数上,却没有验证接口真正产生了什么结果。好的接口用例,一定同时有输入断言和输出断言。
步骤4:写用例
4.1 普通接口用例的基本结构
{
"id": "ORDER-API-01",
"title": "库存充足时创建订单成功",
"priority": "P0",
"precondition": "用户已登录,商品 SKU-001 库存 >= 2",
"request": {
"method": "POST",
"path": "/api/orders",
"headers": { "Authorization": "Bearer xxx" },
"body": {
"sku_id": "SKU-001",
"count": 2,
"address_id": 8899
}
},
"assertions": [
"HTTP 状态码 = 200",
"业务码 = 0",
"返回 order_id 非空",
"订单状态 = PENDING_PAY",
"数据库新增一条订单记录",
"库存预占数量 = 2"
]
}4.2 用例通常分成哪几类
| 类别 | 目的 | 例子 |
|---|---|---|
| 正常用例 | 证明主流程可用 | 正确账号密码登录成功 |
| 异常用例 | 证明非法输入被拦住 | 密码错误返回 401 |
| 边界用例 | 覆盖最容易出错的临界点 | 昵称长度 20、21 |
| 权限用例 | 验证身份和角色差异 | 普通员工不能调管理员接口 |
| 状态用例 | 验证流程正确流转 | 已完成订单不能取消 |
| 鲁棒性用例 | 验证重试、超时、依赖异常 | 支付网关超时时是否正确回滚 |
4.3 一个高质量用例应该写得足够可执行
不要只写"测试库存不足"。要写到别人拿到你的用例后,能直接操作,不需要再猜。
示例
坏用例:
测试库存不足时不能下单好用例:
前置条件:
商品 SKU-002 当前库存 = 1
步骤:
1. 使用用户 A 的登录 token
2. 调用 POST /api/orders
3. body 传 sku_id=SKU-002, count=2, address_id=8899
预期:
1. HTTP 200,业务码 = STOCK_NOT_ENOUGH
2. 返回文案 = "库存不足"
3. 数据库不新增订单记录
4. 库存不发生变化4.4 团队里常用的用例格式怎么写
真实项目里,用例一般不会只写一段自然语言,通常会沉淀成统一格式。这样别人接手时,能快速看懂,也方便做回归和自动化。
| 字段 | 怎么写 | 示例 |
|---|---|---|
| 用例 ID | 按模块统一编号 | ORDER-API-023 |
| 标题 | 场景 + 预期结果 | "库存不足时下单失败" |
| 优先级 | P0 / P1 / P2 | P0 |
| 前置条件 | 账号、数据、依赖状态 | "SKU-002 库存=1,用户A已登录" |
| 步骤 | 具体到可执行 | "POST /api/orders, count=2" |
| 预期 | 状态码 + 业务结果 + 副作用 | "code=STOCK_NOT_ENOUGH,DB 不落单" |
| 备注 | 风险说明、排查口径 | "需联查库存表" |
| 用例ID | 标题 | 优先级 | 前置条件 | 请求 | 预期响应 | 副作用校验 | 备注 |
|--------|------|--------|----------|------|----------|------------|------|
| LOGIN-01 | 正确密码登录成功 | P0 | 账号未冻结 | POST /api/login | 200 + token | 写登录日志 | 核心回归 |
| LOGIN-02 | 错误密码登录失败 | P0 | 账号存在 | POST /api/login | 401 / 业务失败码 | 不写成功登录日志 | 安全场景 |
| ORDER-09 | 重复提交不重复建单 | P0 | 幂等 key 已知 | POST /api/orders ×2 | 两次返回同一 order_id | DB 只有一条订单 | 幂等专项 |步骤5:准备环境和数据
5.1 环境准备清单
| 项目 | 建议 |
|---|---|
| 服务地址 | 区分测试 / 预发 / 生产,避免误调 |
| 账号体系 | 准备不同角色账号:普通用户、管理员、访客、冻结用户 |
| 测试数据 | 准备可复用数据,也准备一次性脏数据 |
| 依赖服务 | 明确哪些是真实依赖,哪些是 Mock |
| 观测手段 | 日志、数据库、缓存、MQ、链路追踪 |
5.2 为什么测试数据经常决定成败
很多接口问题不是用例没设计到,而是数据根本不具备触发条件。比如你想测"优惠券过期",但环境里只有未过期优惠券,这个用例永远跑不出真实结果。
数据准备建议
- 准备一套"干净数据",用于主流程回归
- 准备一套"脏数据",专门触发异常和边界场景
- 能脚本化造数就尽量脚本化,减少人工准备成本
- 有状态的接口,执行前后要能快速重置数据
步骤6:执行与断言
6.1 常见执行工具
| 工具 | 适合什么场景 | 特点 |
|---|---|---|
| Postman / Apifox | 手工调试、接口集合管理 | 上手快,适合前期探索 |
| Swagger / OpenAPI | 对照文档调接口 | 适合理解契约 |
| curl | 快速复现、脚本嵌入 | 轻量、便于自动化 |
| JMeter | 批量接口执行、参数化、并发验证 | 既能做接口功能串联,也能做轻量并发验证 |
| pytest + requests | 回归自动化 | 可维护性更强 |
6.2 断言不能只断言一层
示例
登录接口的完整断言:
- HTTP 状态码 = 200
- 业务码 = 0
- 响应里有 token,且格式正确
- token 真能拿去调后续受保护接口
- 日志中有本次 request_id
- 如果系统设计有登录记录,数据库确实新增成功登录记录
6.3 curl 复现示例
curl -X POST 'https://test.example.com/api/login' \
-H 'Content-Type: application/json' \
-d '{
"username": "tester01",
"password": "Pass@123"
}'6.4 什么时候需要查数据库
- 涉及状态变化:下单、支付、退款、审批
- 涉及金额、积分、库存等关键数据
- 接口响应和页面展示不一致
- 怀疑接口返回成功但实际未落库
- 需要验证是否重复写入
6.5 执行接口时,老师最推荐的顺序
- 先用 Swagger 或接口文档确认字段和示例。
- 再用 Postman / Apifox 单条调通主流程。
- 接着用 curl 固化一条最小复现命令,方便排查和沟通。
- 最后再决定要不要用 JMeter 或自动化脚本批量执行。
步骤7:查问题和定位
7.1 常见故障定位思路
看接口请求 → 看响应和错误码 → 带 request_id 查日志 → 查 DB / 缓存 / MQ → 判断根因
7.2 错误码背后的常见含义
| 现象 | 可能原因 | 优先检查 |
|---|---|---|
| 400 | 参数校验失败、字段格式错误 | 请求体、枚举值、日期格式 |
| 401 | token 缺失、失效、签名错 | Authorization header、token 过期时间 |
| 403 | 权限不足、风控拦截 | 账号角色、资源归属 |
| 404 | 路径错、资源不存在 | URL、环境地址、ID 是否真实存在 |
| 409 | 并发冲突、重复提交 | 幂等键、状态机 |
| 500 | 空指针、依赖异常、数据库错误 | 服务日志、依赖超时、SQL 异常 |
7.3 五类高频接口缺陷
| 缺陷类型 | 表现 | 典型根因 |
|---|---|---|
| 契约不一致 | 文档说是字符串,实际返回数字 | 后端改了字段类型未同步文档 |
| 幂等失败 | 重复请求产生两条数据 | 缺少幂等键或状态锁 |
| 状态机错误 | 非法状态还能继续操作 | 后端未校验前置状态 |
| 越权 | A 用户查到了 B 用户数据 | 只校验登录,未校验资源归属 |
| 数据不一致 | 响应成功但 DB 未更新 | 事务、异步消息、补偿逻辑有缺陷 |
步骤8:回归与输出报告
8.1 什么样的用例应该进回归集
- P0 核心链路用例
- 历史高频缺陷对应的用例
- 有状态流转的关键用例
- 鉴权和越权用例
- 幂等、重复提交、并发冲突用例
8.2 回归集不要只收集"成功用例"
异常用例同样要纳入回归集。很多回归事故不是主流程挂了,而是以前能正确拒绝的非法请求,改完后突然放进来了。
常见类型一:登录 / 鉴权接口怎么测
| 测试点 | 示例 | 预期 |
|---|---|---|
| 正常登录 | 正确账号密码 | 返回 token / session |
| 错误密码 | 密码错误 | 401 或业务失败码 |
| 空账号 | username 为空 | 参数校验失败 |
| 冻结用户 | 账号状态 = disabled | 拒绝登录 |
| token 失效 | 使用过期 token 调接口 | 401 |
| 越权访问 | 普通用户调用管理员接口 | 403 |
常见类型二:查询 / 列表接口怎么测
| 测试点 | 重点 |
|---|---|
| 空数据集 | 返回空数组还是 null,文案是否一致 |
| 分页边界 | 第一页、最后一页、超大页码、size=0/1/100/101 |
| 排序 | 升降序是否正确,相同值顺序是否稳定 |
| 过滤组合 | 状态 + 时间 + 关键字联合查询是否准确 |
| 敏感字段 | 是否误返回手机号、身份证、密钥等敏感信息 |
常见类型三:创建 / 更新 / 删除接口怎么测
写接口的核心关注
正常创建只是第一步,更关键的是幂等、状态校验、事务一致性和副作用。
| 动作 | 重点问题 |
|---|---|
| 创建 | 重复提交、前置条件、落库一致性、默认值 |
| 更新 | 部分更新还是全量覆盖、并发覆盖、旧值保留 |
| 删除 | 真删还是软删、重复删除是否报错、下游查询是否还能看到 |
常见类型四:文件上传下载接口怎么测
| 测试点 | 示例 |
|---|---|
| 文件类型 | jpg/png/pdf/docx/伪装扩展名 |
| 文件大小 | 0B、刚好上限、超过上限 |
| 文件名 | 中文、超长、特殊字符、路径穿越字符 |
| 内容合法性 | 损坏文件、空文件、病毒文件(如果有安全扫描) |
| 下载鉴权 | 无 token 是否能下载,是否越权下载他人文件 |
常见类型五:异步任务 / 回调接口怎么测
示例
典型链路: 提交导出任务→ 返回 task_id→ 后台异步处理→ 轮询状态 / 接收回调→ 获取结果文件
| 测试点 | 预期 |
|---|---|
| 任务创建成功 | 返回唯一 task_id |
| 状态迁移 | waiting → running → success / failed 合法切换 |
| 重复查询 | 轮询不会引发额外副作用 |
| 回调签名 | 非法签名被拒绝 |
| 重复回调 | 重复通知不会重复处理 |
| 超时失败 | 超时后状态清晰,用户可见 |
JMeter 怎么调接口
1. 先搞清楚:JMeter 不只是压测工具
很多人一提 JMeter,只想到压测。其实在接口测试里,JMeter 还有三个非常实用的用途:
- 批量执行一组接口场景。
- 做参数化测试,例如批量账号登录。
- 在轻度并发下验证幂等、锁、限流、重复提交等问题。
什么时候适合用 JMeter
当你需要同一接口反复跑很多次、携带多组数据批量执行、模拟 10~100 级别并发做功能验证时,JMeter 非常顺手。
2. 一个最小可用的 JMeter 结构
Test Plan
└── Thread Group
├── HTTP Request Defaults
├── HTTP Header Manager
├── CSV Data Set Config
├── HTTP Request
├── Response Assertion
└── View Results Tree| 组件 | 作用 | 你最常怎么用 |
|---|---|---|
| Thread Group | 控制用户数、循环次数、启动节奏 | 先用 1 线程调通,再加到 10 / 20 |
| HTTP Request Defaults | 统一域名、协议、端口 | 避免每个请求都重复填 |
| HTTP Header Manager | 统一管理 Content-Type、Authorization | 适合登录态或公共 header |
| CSV Data Set Config | 读取 CSV 做参数化 | 批量账号、批量手机号、批量订单号 |
| Response Assertion | 做结果断言 | 断言状态码、关键字、业务码 |
| View Results Tree | 看请求和响应详情 | 调试阶段必开,批量跑时可关 |
3. 用 JMeter 调一个登录接口
- 新建
Thread Group,线程数先设为1,循环次数1。 - 在
HTTP Request Defaults中配置协议、域名、端口。 - 在
HTTP Header Manager中添加Content-Type: application/json。 - 新建
HTTP Request,方法选POST,路径填/api/login。 - 在
Body Data中写 JSON 请求体。 - 添加
View Results Tree查看响应。 - 添加
Response Assertion,断言响应里包含"code":0或 token 字段。
{
"username": "${username}",
"password": "${password}"
}4. 参数化怎么做
如果你要用 100 个账号批量登录,不要手改 100 次。直接用 CSV Data Set Config:
username,password
tester01,Pass@123
tester02,Pass@123
tester03,Pass@123然后在请求体里写 ${username}、${password}。这样每个线程或每次循环都会自动取一行数据。
5. 用 JMeter 测幂等和重复提交
这是 JMeter 在接口测试里非常好用的场景。比如你想测"提交订单接口会不会重复建单",可以这样做:
- 固定一组订单请求参数。
- 把幂等键写死为同一个值,或者在多个线程中共用同一个业务单号。
- 把
Thread Group提升到 10 或 20 个线程,同时发起请求。 - 断言响应中最多只有一次真正创建成功。
- 查数据库确认订单表里只有一条数据。
JMeter 常见误区
- 一上来就 1000 线程,结果接口都没调通。
- 只看响应时间,不看业务结果和数据库副作用。
- 没有参数化,导致所有线程拿同一个账号互相污染。
- 把功能测试和正式性能压测混在一起,结论失真。
6. 一个更像项目现场的建议
在团队里,JMeter 最推荐的用法通常是这样:
- 前期用 Postman / Apifox 调通接口。
- 中期把核心场景迁移到 JMeter,做批量执行和轻量并发验证。
- 后期把稳定场景再迁移到自动化框架,进入持续回归。
自动化回归怎么做
1. 什么适合自动化
- 稳定、重复、契约清晰的接口
- P0 主流程和历史高频回归场景
- 断言规则明确的查询和写接口
- 适合固定造数和固定清理的接口
2. 一个简单的自动化测试示例
def test_login_success(client):
resp = client.post("/api/login", json={
"username": "tester01",
"password": "Pass@123"
})
assert resp.status_code == 200
body = resp.json()
assert body["code"] == 0
assert body["data"]["token"]3. 自动化里最重要的是数据治理
如果每次自动化都依赖一套会被别人改脏的数据,脚本再多也只会越来越不可信。接口自动化的本质不是"写脚本",而是把环境、数据、断言、报告都工程化。
接口测试报告怎么写
1. 测试范围
- 本次覆盖接口:登录、用户详情、创建订单、取消订单、退款申请
2. 测试结果
- 总用例数:86
- 通过:79
- 失败:5
- 阻塞:2
3. 高风险问题
- P0:重复提交导致重复创建订单
- P1:普通用户可查询他人订单详情
- P1:列表分页在 page=2 时重复数据
4. 结论
- 当前版本不建议上线,需先修复 P0/P1 问题
5. 建议
- 下单接口增加幂等键
- 订单详情接口补充资源归属校验
- 分页 SQL 增加稳定排序字段案例1:登录接口完整教学
1. 先理解业务,而不是先点发送
登录接口看起来很简单,但它其实是整个系统的入口。只要登录这里有漏洞,后面的权限、审计、风控都会被影响。所以老师带新人做接口测试时,最喜欢先拿登录接口来讲,因为它能把参数校验、鉴权、状态、风控、日志这些核心概念一次串起来。
示例
需求背景:
- 用户输入账号和密码登录。
- 登录成功返回 token,有效期 2 小时。
- 连续输错 5 次密码后账号锁定 30 分钟。
- 冻结账号不能登录。
- 登录成功要记录登录日志和最近登录时间。
2. 文档一到手,测试要先问什么
| 问题 | 为什么要问 |
|---|---|
| 用户名支持手机号、邮箱还是工号 | 决定输入等价类怎么划分 |
| 错误密码返回 401 还是 200 + 业务失败码 | 决定断言口径 |
| 锁定规则按账号维度还是按设备维度 | 决定场景设计方式 |
| token 是否支持刷新 | 影响后续鉴权回归 |
| 最近登录时间写在哪张表 | 决定副作用校验 |
3. 测试点拆解示范
| 层次 | 测试点 |
|---|---|
| 参数层 | 用户名为空、密码为空、超长、格式错误 |
| 业务层 | 正确账号密码成功,错误密码失败 |
| 状态层 | 冻结账号、锁定账号、首次登录改密账号 |
| 安全层 | 暴力破解、token 伪造、越权调用 |
| 副作用层 | 登录日志、最近登录时间、失败次数计数 |
4. 一组可直接讲给学员的案例表
| 用例ID | 场景 | 输入 | 预期 | 优先级 |
|---|---|---|---|---|
| LOGIN-01 | 正常登录 | 正确账号密码 | 返回 token,写登录日志 | P0 |
| LOGIN-02 | 密码错误 | 正确账号 + 错误密码 | 登录失败,失败次数 +1 | P0 |
| LOGIN-03 | 连续输错 5 次 | 同账号连续 5 次错误密码 | 第 5 次后锁定 30 分钟 | P0 |
| LOGIN-04 | 冻结账号 | disabled 账号 | 拒绝登录 | P0 |
| LOGIN-05 | 空密码 | password="" | 参数校验失败 | P1 |
| LOGIN-06 | token 生效 | 拿登录成功 token 调用户详情接口 | 成功访问受保护资源 | P1 |
5. 这个案例最容易挖出的缺陷
- 错误密码时返回文案区分了"账号不存在"和"密码错误",造成撞库风险。
- 账号锁定只锁 Web,不锁 App。
- 登录成功了,但最近登录时间没有更新。
- token 返回成功,但后续接口不认这个 token。
案例2:下单接口完整教学
1. 为什么下单接口是接口测试的必讲案例
因为它几乎把接口测试里最重要的东西都聚齐了:参数、价格、库存、优惠券、地址、状态流转、事务一致性、幂等性、副作用、消息通知。一个下单接口讲清楚了,学员对"什么叫真正的接口测试"基本就有感觉了。
示例
业务规则设定:
- 只有已登录用户才能下单。
- 商品必须上架且库存充足。
- 优惠券必须属于当前用户且未过期。
- 同一个请求支持幂等,避免重复建单。
- 下单成功后要创建订单、预占库存、发出待支付消息。
2. 下单接口的分析框架
| 分析维度 | 要验证什么 |
|---|---|
| 入参 | sku_id、count、coupon_id、address_id 是否合法 |
| 价格 | 原价、优惠价、运费、应付金额是否一致 |
| 库存 | 库存不足时是否拒绝,成功时是否预占 |
| 幂等 | 重复请求是否只创建一张订单 |
| 副作用 | 订单表、库存表、消息表是否一致 |
| 状态 | 新建订单状态是否正确 |
3. 下单接口完整用例矩阵
| 类别 | 场景 | 预期 |
|---|---|---|
| 正常 | 库存充足、优惠券有效 | 下单成功,状态 = PENDING_PAY |
| 异常 | 库存不足 | 下单失败,不创建订单 |
| 异常 | 优惠券过期 | 下单失败,不抵扣金额 |
| 边界 | count=1、99、100 | 1 和 99 合法,100 被拒绝 |
| 权限 | 使用他人地址 ID | 越权拒绝 |
| 幂等 | 相同幂等键连续提交两次 | 返回同一 order_id |
| 并发 | 最后 1 件库存,2 个用户同时下单 | 最多 1 单成功 |
4. 讲幂等性时,这个案例最好用
请求1:
POST /api/orders
Idempotency-Key: ORD-001
请求2:
POST /api/orders
Idempotency-Key: ORD-001
理想结果:
两次响应都成功
但返回同一 order_id
订单表只有一条记录
库存只扣一次
MQ 只发一次这段内容拿来讲课很好,因为它能让学员一下子明白:幂等不是"第二次必须报错",而是"第二次不能把同一件业务再执行一遍"。
5. 一个非常像线上事故的缺陷案例
示例
**问题现象:**用户说自己只点了一次下单,却生成了两笔订单。 排查过程:
- 查 Nginx 日志,发现客户端在 3 秒超时后自动重试。
- 查订单表,确实有两张金额完全一样的订单。
- 查接口文档,没有任何幂等说明。
- 查服务代码,发现后端没有使用业务单号或幂等键去重。 **结论:**这是典型的"客户端重试 + 服务端无幂等保护"事故。
案例3:退款接口完整教学
1. 退款接口为什么比下单还适合讲规则
因为退款接口往往不是简单的成功或失败,而是被多个条件共同决定。非常适合拿来教判定表、状态流转和异常分支。
示例
退款规则假设:
- 只有已支付订单才能退款。
- 订单必须在 7 天退款期内。
- 已发货订单不能走普通退款,只能走售后。
- 退款成功后要更新订单状态并调用支付渠道退款。
2. 用判定表来讲这个接口最清楚
| # | 已支付 | 7天内 | 已发货 | 结果 |
|---|---|---|---|---|
| 1 | 否 | 是 | 否 | 拒绝,订单未支付 |
| 2 | 是 | 否 | 否 | 拒绝,超过时限 |
| 3 | 是 | 是 | 否 | 允许退款 |
| 4 | 是 | 是 | 是 | 转售后流程 |
3. 测试时一定要查两个系统
退款接口最容易出现的坑是"订单系统以为退了,支付系统其实没退"。所以至少要同时校验:
- 订单系统状态是否从
PAID变成REFUNDING或REFUNDED。 - 支付渠道是否真的发起了退款请求。
- 退款失败时是否有补偿或重试。
4. 退款接口典型缺陷清单
| 缺陷 | 表现 | 根因 |
|---|---|---|
| 重复退款 | 同一订单退了两次 | 退款申请接口不幂等 |
| 状态提前完成 | 渠道未成功,订单却已标记已退款 | 状态推进时机错误 |
| 售后分支漏拦截 | 已发货订单仍走普通退款 | 规则判断缺失 |
| 补偿失效 | 支付渠道失败后无后续处理 | 补偿任务未触发 |
5. 老师带练建议
- 让学员先自己写 4 条退款用例。
- 再把判定表拿出来,让学员对照补漏。
- 最后要求每个学员补写一条"支付渠道失败"的异常用例。
课堂练习
- 选择你当前项目的一个核心接口,按本篇的 8 步法完整走一遍。
- 再仿照案例 1、案例 2、案例 3 的写法,完整写一份"需求背景 + 测试点拆解 + 用例表 + 缺陷风险"。
- 至少写出 15 条用例:正常 4 条、异常 4 条、边界 2 条、权限 2 条、状态/幂等 3 条。
- 用 Postman、Apifox、curl 或 JMeter 实际执行,并记录一条完整缺陷。
补充参考答案要点
- 通用篇练习的关键是能把兼容性、幂等性、状态机、异常流和链路副作用串到同一个测试框架里。
- 如果题目让你写用例,不应只写 happy path,还要覆盖非法参数、重复请求、顺序错乱和并发场景。
- 好的答案通常会说明断言对象不只包括响应,还包括日志、数据库、缓存和消息队列。