本文记录了一个完整的电商接口自动化测试项目从设计到落地的全过程,涵盖三层架构、Fixture 依赖注入、数据驱动和 Allure 报告等核心实践。
一、项目背景
最近在学习接口自动化测试,决定拿开源电商系统 OpenCart 练手。目标很明确:
- 覆盖核心业务流:商品浏览 → 加购 → 购物车查看
- 工程化:不是写几个脚本跑通就行,而是要体现分层设计、数据驱动、报告输出
- 可维护:需求变了(比如商品 ID 改了),改一处即可
最终技术栈定为:Python + requests + pytest + Allure。
二、整体架构设计
没有架构的测试项目,脚本写到 20 个就崩了。我参考了 Page Object 的思想,把项目拆成三层:
┌─────────────────────────────────────────┐
│ tests/ 测试用例层 │
│ 只写断言,不碰 HTTP 细节 │
├─────────────────────────────────────────┤
│ api/ 业务 API 层 │
│ 封装商品/购物车接口,支持依赖注入 │
├─────────────────────────────────────────┤
│ api/client.py HTTP 客户端层 │
│ Session 管理、Cookie 自动携带、重试 │
├─────────────────────────────────────────┤
│ data/ 测试数据中心 │
│ 商品、分类、账号,一处修改全局生效 │
└─────────────────────────────────────────┘
为什么这么分?
- 如果后端接口路径变了(比如
checkout/cart.add改成cart/add),只改cart_api.py一处,所有用例无感知 - 如果测试环境从
localhost切到192.168.x.x,只改BASE_URL一处 - 如果商品 ID 变了,只改
test_data.py一处
三、核心技术实现
3.1 HTTP 客户端:Session + 重试
OpenCart 的接口基于 Cookie 维持登录态,所以必须用 requests.Session(),否则每个请求都是独立会话,登录状态无法保持。
class APIClient:
BASE_URL = os.getenv("OPENCART_BASE_URL", "http://127.0.0.1/opencart")
def __init__(self):
self.session = requests.Session()
# 网络抖动时自动重试 3 次
retries = Retry(total=3, backoff_factor=0.5)
self.session.mount("http://", HTTPAdapter(max_retries=retries))
self.session.headers.update({
"X-Requested-With": "XMLHttpRequest"
})
def post(self, path, **kwargs):
return self.session.post(self.BASE_URL + path, **kwargs)
亮点:
Session自动管理 Cookie,登录后后续请求无需手动带 tokenRetry机制提升稳定性,避免偶发网络抖动导致用例失败BASE_URL通过环境变量注入,支持多环境切换
3.2 业务 API 层:依赖注入
以购物车模块为例,CartAPI 不自己创建客户端,而是接受外部传入:
class CartAPI:
def __init__(self, client: APIClient = None):
self.client = client or APIClient()
def add_to_cart(self, product_id, quantity):
return self.client.post(
"/index.php?route=checkout/cart.add",
data={"product_id": product_id, "quantity": quantity}
)
为什么这么设计?
测试用例里可以灵活选择:
- 传已登录的 client → 测需要鉴权的接口(加购、查看购物车)
- 不传(默认新建)→ 测游客场景
3.3 Fixture 管理登录态
最开始的版本,每个测试方法里都重复写 4 行登录代码。改成 pytest fixture 后:
# conftest.py
@pytest.fixture
def api_client():
client = APIClient()
client.post(
"/index.php?route=account/login.login",
data=TEST_USER # 从 data/test_data.py 引入
)
return client
测试用例只需声明参数即可使用:
def test_add_to_cart_success(self, api_client):
api = CartAPI(api_client)
resp = api.add_to_cart(PRODUCTS["macbook"]["product_id"], 1)
assert resp.status_code == 200
assert "Success" in resp.text
代码量减少 40%,而且登录逻辑集中管理,换测试账号改一处即可。
3.4 数据驱动:test_data.py
所有硬编码数据抽到独立模块:
# data/test_data.py
TEST_USER = {
"email": "testuser01@demo.local",
"password": "Test@123456"
}
PRODUCTS = {
"macbook": {"product_id": 43, "name": "MacBook"},
"iphone": {"product_id": 40, "name": "iPhone"},
}
CATEGORIES = {
"desktops": 20,
"software": 17,
}
用例里通过常量引用:PRODUCTS["macbook"]["product_id"],而不是裸写 43。
3.5 Allure 报告分级
用 @allure.epic / feature / story 做三级注解,生成结构化的报告:
@allure.epic("OpenCart 接口测试")
@allure.feature("购物车接口")
class TestCartAPI:
@allure.story("加购")
@allure.title("TC-API-CART-001: 正常加购")
@allure.severity(allure.severity_level.CRITICAL)
def test_add_to_cart_success(self, api_client):
...
报告效果:
- 项目级 → 模块级 → 功能级,层层展开
- 用例带编号、带优先级,方便追溯
四、典型用例解析
以购物车加购为例,完整调用链路:
pytest 发现 test_add_to_cart_success 依赖 api_client fixture
↓
conftest.py 创建 APIClient → POST 登录 → Session 保存 Cookie
↓
CartAPI(api_client) 注入已登录客户端
↓
add_to_cart(43, 1) → POST checkout/cart.add
↓
Session 自动携带 Cookie → 服务器识别用户身份
↓
断言:status_code == 200 且响应包含 "Success"
整个过程测试层只关注业务断言,HTTP 细节、登录逻辑、Cookie 管理全部下沉到底层。
五、踩坑记录(环境配置篇)
本地部署 OpenCart 时,MySQL 反复启动失败,报错 ibdata1 大小不匹配。排查过程:
- 发现
my.ini里datadir指向了错误的c:/xampp/mysql/data - 清理损坏的 InnoDB 文件(
ibdata1、ib_logfile*) - 重置 root 密码(MariaDB 10.4 的权限表结构变了,不能用传统
UPDATE user SET password) - 重新安装 OpenCart,数据库恢复正常
教训:本地环境出问题不要慌,看日志、看配置、看端口,逐步缩小范围。
六、总结
这个项目虽然不大,但覆盖了接口自动化测试的核心能力:
| 能力 | 体现 |
|---|---|
| 分层架构 | client → api → tests 三层分离 |
| 设计模式 | API 层的依赖注入、数据驱动 |
| 框架特性 | pytest fixture、Allure 报告分级 |
| 工程化 | 环境变量解耦、一键运行脚本 |
源码已开源到 GitHub,欢迎交流:
- 项目地址:opencart-api-test
下一步计划:基于同一套 OpenCart 系统,再做一个 UI 自动化测试项目(Selenium + Page Object + Allure),形成接口 + UI 的完整测试体系,敬请期待。