API 测试怎么写:状态码、数据隔离与业务逻辑下沉
第四天下午,同学们把 FizzBuzz 从前端纯函数改成了前后端项目:页面提交数字,后端计算并保存历史记录。功能看起来只是“把代码搬到后端”,实际却同时引入了接口契约、端口、跨域、状态码、用户身份和数据隔离。
这正是 API 测试的价值。它不只是证明网络能通,而是验证服务边界是否按约定处理输入、权限、业务规则和持久化结果。
前置条件
- 前端和后端能够分别启动,并记录真实端口。
- 后端至少提供健康检查和一个业务接口。
- 已明确请求字段、响应结构、成功与失败状态码。
- 准备独立测试数据库、事务回滚或可清理的测试数据策略。
- 核心纯业务规则已有单元测试。
第一步:先写接口契约
以注册为例,不要只写“提供注册接口”,至少要明确:
- 方法与路径,例如 POST /users。
- 必填字段、格式和长度限制。
- 成功响应包含什么,是否返回敏感字段。
- 邮箱重复、参数无效、服务异常分别怎样表达。
- 是否需要认证,谁有权限访问。
GET 通常用于读取资源,POST 常用于提交导致状态变化或复杂处理的请求,但不要把它简化成“参数放哪里”的选择。方法、资源路径和状态码共同构成接口语义。
第二步:先验证服务状态,再验证业务
排查时按层次推进:
- 健康检查能否响应。
- 业务路由是否存在。
- 参数校验是否按契约返回。
- Service 是否执行正确规则。
- 数据是否真实写入并可再次读取。
健康检查返回 200 不等于注册功能可用;业务接口返回 200 也不等于数据已经持久化。每一层都要有对应证据。
第三步:覆盖成功、失败、权限和重复行为
注册接口至少可以选择这些高价值场景:
| 场景 | 操作 | 预期 |
|---|---|---|
| 正常注册 | 提交新的合法账号 | 创建成功,响应不含密码 |
| 参数缺失 | 不提交邮箱 | 返回客户端错误和明确字段信息 |
| 重复注册 | 再次提交相同邮箱 | 返回冲突,数据库没有重复用户 |
| 未授权访问 | 访问受保护资源 | 返回未认证或无权限 |
| 登录失败 | 提交错误密码 | 不创建会话,不泄露账号细节 |
状态码需要和响应体一起判断。一个 400 如果没有指出哪个字段不合法,前端仍然难以给用户正确反馈;一个 200 如果响应体表示失败,也会让监控和调用方误判。
第四步:把关键业务逻辑留在后端
前端可以做即时校验和友好提示,但库存扣减、价格计算、权限、积分等最终规则必须由可信服务端执行。否则调用者绕过页面直接请求接口,就可能获得不同结果。
后端内部可以按项目复杂度区分职责:Controller 处理 HTTP 输入输出,Service 处理业务规则,Repository 处理数据访问。小项目不必为分层而分层,但同一条规则不能散落在页面、接口和数据库脚本里各写一遍。
单元测试覆盖 Service 中大量规则组合;API 测试重点验证序列化、参数、认证、事务和数据库边界。不要用几十条 API 请求重复已经由纯函数证明的所有组合。
第五步:让测试数据可重复、可隔离
最危险的做法,是每次测试前“清空数据库”。在共享开发库或生产库里,这可能直接删除他人数据。更安全的选择包括:
- 每个测试使用独立事务,结束后回滚。
- 使用专用测试数据库和可重复 fixture。
- 为账号、订单生成唯一标识,只清理本次创建的数据。
- 并行测试使用不同命名空间或租户。
测试开始时显式准备数据,结束时由 fixture 负责清理。这样单独运行、整套运行和改变顺序都应得到一致结果。
第六步:连接前端前先把 API 证据跑通
可以用项目已有测试框架、HTTP 客户端或 Playwright 的 APIRequestContext 发请求。工具不是重点,固定命令和可读断言才是重点。接口稳定后再连接前端,出现问题时就能判断是浏览器交互、跨域和代理,还是后端契约本身。
前后端端口不同的本地项目还要明确代理或 CORS 配置。不要为了“先跑起来”开放任意来源并直接复制到生产环境。
成功标准
- API 契约包含方法、路径、字段、状态码、权限和错误语义。
- 健康检查、业务规则和持久化分别有证据。
- 成功、参数失败、重复行为和权限场景被覆盖。
- 核心业务规则由服务端负责,前端校验只是辅助体验。
- 测试数据与共享、生产数据隔离,可重复运行。
- API 与单元测试各自覆盖合适边界,没有机械重复。
常见报错与处理
浏览器报跨域,接口工具却正常
说明后端业务可能可用,但浏览器来源未被允许。核对前端实际地址、后端 CORS 白名单和开发代理,不要直接允许所有来源作为最终方案。
第二次运行出现重复账号
测试数据没有唯一化或清理。使用随机后缀、fixture、事务回滚或专用测试库,不要手工清空共享表。
状态码正确但断言仍失败
继续检查响应结构、数据库状态和副作用。状态码只是契约的一部分,不能代替业务验证。
API 测试非常慢
检查是否把全部纯逻辑组合都放到了数据库与网络层。把规则矩阵下沉到单元测试,只保留服务边界的代表性场景。
课后练习
为项目选择一个会写数据的接口,完成正常、参数错误、重复提交和无权限四个场景。把四条测试随机排序运行三次,确认都能独立通过。再回答:哪些规则应该移到单元测试,哪些结果只有 API 测试才能证明?