如何设计完善的接口自动化
目标和原则
一套完善的接口自动化,不是“能跑通几个接口”,而是要同时满足:
- 快:核心回归能在几分钟内完成。
- 稳:失败能定位,不能大量误报。
- 全:覆盖正常、异常、边界、鉴权、幂等和业务副作用。
- 可维护:新增接口成本低,用例结构清晰。
- 可集成:能接入 CI,形成质量门禁。
- 可观测:失败时有请求、响应、日志、traceId 和数据库状态。
核心原则:
- 测试用例表达业务,不堆工具细节。
- 断言不只看状态码,要看业务结果和副作用。
- 测试数据要隔离、可重复、可清理。
- 失败要能快速定位,不能只报“500”。
- 能用 API 准备的,不要用 UI。
分层架构
tests/ 业务场景和用例
services/ 接口封装、鉴权、重试、超时
assertions/ 通用断言:状态码、schema、业务字段、数据库
data/ 测试数据、工厂、fixtures
config/ 环境、账号、密钥
utils/ 日志、签名、时间、随机数据
reports/ Allure/JUnit/HTML 报告
conftest.py 全局 fixture、清理、钩子
1. 用例层
用例只描述业务:
def test_create_order_with_coupon(api, user, product):
cart = api.cart.add(user, product.id, quantity=1)
order = api.orders.create(user, coupon="NEW10")
assert order.status == "pending"
assert order.amount == cart.total - 10
assert db.orders.get(order.id).status == "pending"
assert inventory(product.id) == 9
2. 接口层
统一处理 baseURL、超时、重试、鉴权、日志和错误:
class ApiClient:
def __init__(self, base_url, token=None, timeout=10):
self.base_url = base_url
self.session = requests.Session()
self.timeout = timeout
if token:
self.session.headers["Authorization"] = f"Bearer {token}"
def request(self, method, path, **kwargs):
url = f"{self.base_url}{path}"
response = self.session.request(
method, url, timeout=self.timeout, **kwargs
)
log_request_response(response)
return response
3. 断言层
至少覆盖:
- HTTP 状态码
- 响应 schema
- 业务 code / message
- 关键字段值和类型
- 数据库状态
- 幂等性
- 权限和越权
- 性能基线(可选)
def assert_order_created(response, expected):
assert response.status_code == 201
body = response.json()
assert body["code"] == 0
validate(instance=body, schema=ORDER_SCHEMA)
assert body["data"]["amount"] == expected.amount
4. 数据层
- 用工厂生成唯一数据,例如
order_{uuid}。 - 测试结束后清理,或用独立租户/环境隔离。
- 不要依赖其他用例产生的数据。
- 需要并发时,每个线程使用独立账号和数据。
5. 配置层
env: staging
base_url: https://staging.example.com/api
accounts:
normal: { username: qa01, password: "***" }
admin: { username: admin, password: "***" }
密钥不要提交到仓库,用环境变量或密钥管理服务。
关键设计点
契约优先
- 用 OpenAPI/JSON Schema 校验响应结构。
- 接口变更时先跑契约测试。
- 生成客户端或 mock,减少手写字段错误。
鉴权
- 登录一次,复用 token;处理刷新和过期。
- 准备普通用户、管理员、无权限用户等角色。
- 每个角色都要测越权访问。
测试数据
- 唯一化:时间戳、UUID、租户 ID。
- 可清理:删除接口或数据库清理。
- 幂等:重复创建要有唯一约束或幂等键。
失败定位
失败报告至少包含:
- 请求方法、URL、headers、body
- 响应状态码、headers、body
- traceId / requestId
- 相关日志
- 数据库前后状态(必要时)
CI 集成
- 提交时跑冒烟集,夜间跑全量。
- 用 tag 区分 smoke / regression / contract。
- 失败阻断合并,flaky 用例隔离并跟踪。
- 报告归档,保留历史趋势。
目录和命名示例
tests/
orders/
test_create_order.py
test_cancel_order.py
auth/
test_login.py
test_permission.py
services/
auth_service.py
order_service.py
cart_service.py
assertions/
common.py
order_assertions.py
data/
factories.py
fixtures/
config/
staging.yaml
local.yaml
反模式
- 只断言
status_code == 200。 - 用例之间共享账号和购物车。
- 用
sleep等待异步结果。 - 失败后不清理数据,导致下次失败。
- 为了“稳定”滥用重试,掩盖真实 bug。
- 所有场景都走 UI,接口测试覆盖不足。
- 测试数据写死,换环境就失败。
- 没有报告和日志,失败无法定位。
检查清单
- [ ] 核心业务链路有覆盖
- [ ] 正常、异常、边界、鉴权、幂等都有用例
- [ ] 断言包含业务字段和数据库副作用
- [ ] 测试数据唯一、可清理、可并发
- [ ] 失败报告包含请求、响应、traceId、日志
- [ ] 冒烟集能在 5 分钟内跑完
- [ ] 已接入 CI 并有质量门禁
- [ ] flaky 用例有隔离和跟踪机制
面试回答模板
我会把接口自动化分成用例层、接口层、断言层、数据层、配置层和报告层。用例表达业务,接口层统一处理鉴权、超时、重试和日志,断言层覆盖状态码、schema、业务字段、数据库副作用和幂等性。测试数据用工厂生成并清理,保证隔离和可并发。最后接入 CI,分冒烟和全量,失败报告带上请求响应、traceId 和日志,保证能快速定位。