接口自动化项目实战¶
概述
本实战用于把接口测试方法论、Postman 调试、Python Requests、Pytest、Allure 报告和 CI/CD 串成一个可落地的小型接口自动化项目。
新手导读¶
| 项目 | 说明 |
|---|---|
| 适合人群 | 会用 Postman 调接口,准备把核心接口改成自动化脚本的新手 |
| 前置知识 | HTTP、JSON、Postman 环境变量、Python 函数、Pytest 基础 |
| 最终产出 | 一套可运行的接口自动化目录、登录用例、订单用例、数据驱动示例、Allure 报告 |
| 跟练方式 | 先写一个最小登录用例,能跑通后再抽请求封装、测试数据和报告 |
| 常见卡点 | 一开始就搭大框架;Token 写死;只断言 200;测试数据互相污染 |
本实战建议边写边运行。每新增一个文件,都执行一次 pytest,确认问题发生在哪一步,避免最后堆出一堆难排查的错误。
一、项目目标¶
本项目以电商系统核心接口为对象,完成一套可维护的接口自动化框架。目标不是把所有接口都自动化,而是先覆盖稳定、关键、高频的主流程。
如果你基础薄弱,先记住一句话:
所以学习顺序应该是:
不要一开始就写复杂框架。框架是从重复代码中提炼出来的,不是第一天凭空设计出来的。
核心目标¶
| 目标 | 说明 |
|---|---|
| 请求封装 | 统一处理 Base URL、Header、Token、超时和日志 |
| 用例组织 | 按业务模块拆分登录、商品、购物车、订单接口 |
| 数据驱动 | 用 YAML / JSON / CSV 管理测试数据 |
| 断言策略 | 同时断言状态码、业务码、字段、数据库结果 |
| 报告输出 | 使用 Allure 展示接口用例执行结果 |
| 持续集成 | 支持在 Jenkins 或 GitHub Actions 中执行 |
二、新手先搞懂接口自动化在测什么¶
一个接口请求通常包含:
| 部分 | 说明 | 示例 |
|---|---|---|
| 请求方法 | 表示操作类型 | GET、POST |
| URL | 接口地址 | /api/login |
| Header | 请求头,常放 Token、Content-Type | Authorization |
| 参数 | 查询参数、JSON、表单数据 | username、password |
| 响应状态码 | HTTP 层结果 | 200、401、500 |
| 响应 body | 业务结果 | code、message、data |
接口自动化不是只看接口有没有返回。你至少要判断:
- HTTP 状态码是否正确。
- 业务 code 是否正确。
- 响应字段是否完整。
- 数据库结果是否符合业务。
- 异常场景是否被正确拒绝。
三、从 Postman 到 Python:跟练路线¶
建议按下面 6 步走:
- 用 Postman 调通登录接口。
- 从登录响应里拿到 Token。
- 带 Token 调用商品详情接口。
- 带 Token 调用创建订单接口。
- 把这 3 个请求改写成 Python 代码。
- 用 Pytest 把代码变成可重复执行的自动化用例。
你先能完成这 6 步,再考虑封装、数据驱动和报告。
四、接口范围¶
第一阶段建议只覆盖 P0 和 P1 接口:
| 模块 | 接口 | 优先级 | 是否自动化 |
|---|---|---|---|
| 登录 | /api/login |
P0 | 是 |
| 商品 | /api/products |
P0 | 是 |
| 商品 | /api/products/{id} |
P0 | 是 |
| 购物车 | /api/cart |
P0 | 是 |
| 订单 | /api/orders |
P0 | 是 |
| 订单 | /api/orders/{id} |
P0 | 是 |
| 订单 | /api/orders/{id}/cancel |
P1 | 是 |
| 支付 | /api/pay/callback |
P1 | 视环境决定 |
不建议第一版就覆盖低频后台配置接口。自动化优先做稳定流程,变化频繁的接口先保留手工验证。
五、从 0 开始准备项目¶
5.1 创建目录¶
5.2 创建虚拟环境¶
5.3 安装依赖¶
创建 requirements.txt:
5.4 第一个最小用例¶
先写最简单的请求,不要急着封装:
import requests
def test_login_success():
response = requests.post(
"https://test-api.example.com/api/login",
json={"username": "test_user", "password": "test_password"},
timeout=10,
)
assert response.status_code == 200
assert response.json()["code"] == 0
能运行成功后,再进入框架化。
六、项目目录结构¶
api_auto_project/
├── common/
│ ├── client.py # 请求封装
│ ├── logger.py # 日志封装
│ └── assert_utils.py # 通用断言
├── config/
│ └── env.yaml # 环境配置
├── data/
│ ├── login.yaml
│ ├── product.yaml
│ └── order.yaml
├── tests/
│ ├── test_login.py
│ ├── test_product.py
│ └── test_order.py
├── utils/
│ ├── db.py # 数据库连接
│ └── token.py # Token 获取
├── pytest.ini
├── requirements.txt
└── README.md
目录设计原则:
common/放通用能力。data/放测试数据。tests/放测试用例。utils/放数据库、加密、时间处理等工具函数。- 不在用例里硬编码环境地址、账号、密码和 Token。
七、环境配置¶
示例 config/env.yaml:
test:
base_url: "https://test-api.example.com"
timeout: 10
username: "test_user"
password: "test_password"
prod:
base_url: "https://api.example.com"
timeout: 10
运行时通过参数指定环境:
测试环境账号可以写在配置文件里,但生产环境密码、Token、数据库密码应使用环境变量或 CI Secret。
八、请求封装¶
示例封装思路:
import requests
class ApiClient:
def __init__(self, base_url, timeout=10):
self.base_url = base_url.rstrip("/")
self.timeout = timeout
self.session = requests.Session()
def set_token(self, token):
self.session.headers.update({"Authorization": f"Bearer {token}"})
def request(self, method, path, **kwargs):
url = f"{self.base_url}{path}"
return self.session.request(method, url, timeout=self.timeout, **kwargs)
封装后,用例只关注业务行为:
def test_get_product_detail(api_client):
response = api_client.request("GET", "/api/products/10001")
assert response.status_code == 200
assert response.json()["code"] == 0
九、用例设计¶
9.1 登录接口¶
| 场景 | 数据 | 预期 |
|---|---|---|
| 正确账号密码 | 有效账号、有效密码 | 登录成功,返回 Token |
| 密码错误 | 有效账号、错误密码 | 登录失败 |
| 账号不存在 | 不存在账号 | 登录失败 |
| 参数缺失 | 不传 password | 参数校验失败 |
9.2 创建订单接口¶
| 场景 | 数据 | 预期 |
|---|---|---|
| 正常下单 | 商品上架、库存充足 | 创建成功 |
| 未登录下单 | 不带 Token | 返回 401 |
| 商品下架 | 下架商品 ID | 创建失败 |
| 库存不足 | 数量大于库存 | 创建失败 |
| 重复提交 | 相同请求重复发送 | 不重复扣库存 |
十、数据驱动¶
示例 data/login.yaml:
- case_name: 正确账号密码登录
username: test_user
password: test_password
expected_code: 0
- case_name: 密码错误
username: test_user
password: wrong_password
expected_code: 1001
测试用例示例:
import pytest
@pytest.mark.parametrize("case", login_cases)
def test_login(api_client, case):
response = api_client.request(
"POST",
"/api/login",
json={"username": case["username"], "password": case["password"]},
)
assert response.json()["code"] == case["expected_code"]
数据驱动适合参数组合清晰的接口;复杂业务流程不要过度数据化,否则可读性会下降。
十一、断言策略¶
接口自动化建议分层断言:
| 层级 | 示例 |
|---|---|
| 协议层 | HTTP 状态码、响应时间、Content-Type |
| 业务层 | 业务 code、message、关键字段 |
| 数据层 | 数据库记录、库存、订单状态 |
| 安全层 | 鉴权、越权、敏感字段 |
创建订单接口不能只断言 code == 0,还应校验:
- 返回订单号不为空。
- 订单金额正确。
- 订单状态为待支付。
- 库存被正确扣减。
- 订单归属当前用户。
十二、常见新手错误¶
| 错误 | 问题 | 改法 |
|---|---|---|
| 只断言状态码 200 | 业务失败也可能返回 200 | 同时断言业务 code 和关键字段 |
| 用例之间强依赖 | 一个失败导致后面全失败 | 单接口用例尽量独立,流程用例单独管理 |
| Token 写死 | Token 过期后全部失败 | 登录接口动态获取 Token |
| 测试数据混用 | 多人执行互相影响 | 使用独立测试账号和可恢复数据 |
| 把所有接口都自动化 | 维护成本过高 | 先做 P0/P1 稳定接口 |
十三、Allure 报告¶
建议在用例中补充标题、模块和步骤:
import allure
@allure.feature("订单模块")
@allure.story("创建订单")
@allure.title("库存充足时创建订单成功")
def test_create_order_success(api_client):
with allure.step("创建订单"):
response = api_client.request("POST", "/api/orders", json={"product_id": 10001, "quantity": 1})
with allure.step("断言订单创建成功"):
assert response.status_code == 200
assert response.json()["code"] == 0
运行命令:
十四、练习任务¶
按顺序完成:
- 写一个登录成功用例。
- 写一个登录失败用例。
- 写一个商品详情查询用例。
- 写一个未登录创建订单失败用例。
- 写一个正常创建订单用例。
- 给每个用例补充业务 code 断言。
- 生成一次 Allure 报告。
完成标准:
- 运行
pytest能看到 5 条用例执行结果。 - 至少 1 条用例使用动态 Token。
- 至少 1 条用例校验业务字段。
- 报告里能看出模块、用例名和失败原因。
十五、CI 集成¶
GitHub Actions 示例流程:
name: API Tests
on:
workflow_dispatch:
push:
branches:
- main
jobs:
api-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- run: pip install -r requirements.txt
- run: pytest --alluredir=reports/allure-results
真实项目中还需要处理测试环境地址、账号、密码和报告归档。
十六、维护规范¶
| 问题 | 建议 |
|---|---|
| 接口字段频繁变化 | 只断言关键字段,不对非核心字段做强绑定 |
| 测试数据污染 | 每次执行前准备数据,执行后清理或使用独立测试数据 |
| 用例互相依赖 | 主流程可以串联,单接口用例尽量独立 |
| 环境不稳定 | 区分脚本失败、环境失败和业务缺陷 |
| 敏感信息泄露 | 密码、Token、密钥使用环境变量或 CI Secret |
接口自动化的价值不只是“自动跑”,更重要的是稳定反馈核心业务是否被破坏。