接口自动化测试完整详解(Python+pytest+requests+Allure 企业落地版)
整体核心:分层自动化框架思想 + 核心技术实现 + CI持续集成 + 项目管理规范
一、框架选型与标准目录结构
1. 主流技术栈选型(图中标准组合)
Python + pytest + requests + Allure
各组件职责拆分:
| 组件 | 作用 |
|---|---|
| Python | 开发语言,语法简洁,第三方库丰富 |
| pytest | 单元/自动化测试框架,支持用例管理、参数化、夹具、后置前置 |
| requests | HTTP请求库,发送GET/POST/PUT等接口请求 |
| Allure | 高颜值可视化测试报告,展示步骤、断言、日志、失败截图 |
| yaml/csv/excel | 测试数据文件,实现数据驱动DDT |
| logging | 日志模块,记录完整请求/响应报文 |
| pymysql | 数据库连接库,实现落库校验、造数、清理数据 |
2. 标准分层目录结构(企业通用规范)
api_auto_test/
├── common/ # 公共封装层(核心工具类)
│ ├── http_client.py # 统一请求封装(url、token、header、ssl)
│ ├── assert_util.py # 通用断言工具(多层json、数据库断言)
│ ├── log_util.py # 日志封装,打印完整请求响应
│ ├── db_util.py # 数据库操作封装(查询/新增/清理)
│ └── tools.py # 工具函数:提取json、时间、随机数、加密签名
├── config/ # 环境配置文件
│ ├── env.yaml # 多环境域名、账号、数据库地址、全局token
│ └── setting.py # 全局变量:报告路径、日志等级、文件路径
├── data/ # 测试数据层(数据驱动文件)
│ ├── login_data.yaml # 登录接口多组测试数据
│ └── order.csv # 订单批量参数化数据
├── testcases/ # 测试用例层(按业务模块拆分)
│ ├── test_login.py # 登录模块用例(提取token实现关联)
│ ├── test_user.py # 用户信息接口
│ └── test_order.py # 订单业务链路(登录→创建→查询→取消)
├── reports/ # 报告输出目录
│ ├── log/ # 运行日志文件
│ ├── raw/ # allure原始结果
│ └── html/ # 最终allure可视化html报告
├── conftest.py # pytest全局夹具(前置登录、全局token、环境清理)
└── run.py # 项目启动入口,一键执行全部用例并生成报告
二、核心技术要点拆解(全考点覆盖)
1. 请求封装 common/http_client.py
统一封装HTTP请求,解决重复代码、统一处理公共逻辑:
- URL自动拼接:读取config环境域名,不用每个用例写完整地址
- Token全局自动携带:登录后存入全局变量,后续接口自动塞入Header
- 接口签名统一处理:加密算法封装,所有请求自动加sign签名
- SSL证书忽略:测试环境跳过证书校验
- 统一日志打印:自动记录请求头、请求体、响应码、响应JSON
- 统一异常捕获:超时、连接失败、500异常统一捕获记录日志
极简封装示例代码:
python
import requests
from common.log_util import logger
from config.setting import BASE_URL
class HttpClient:
token = "" # 全局静态token
@classmethod
def send_request(cls, method, path, params=None, json=None, headers=None):
# 1. 拼接完整url
url = BASE_URL + path
# 2. 统一公共请求头
base_headers = {"Content-Type": "application/json"}
if cls.token:
base_headers["Authorization"] = f"Bearer {cls.token}"
if headers:
base_headers.update(headers)
# 3. 打印请求日志
logger.info(f"请求地址:{url}, 请求方法:{method}")
logger.info(f"请求头:{base_headers}, 请求参数:{json}")
# 4. 发送请求
resp = requests.request(
method=method,
url=url,
params=params,
json=json,
headers=base_headers,
verify=False # 关闭ssl校验
)
logger.info(f"响应码:{resp.status_code}, 响应内容:{resp.text}")
return resp.json()
2. 接口关联(参数动态提取与传递)
实现思路:
- 登录用例执行完成,提取返回
token存入全局静态变量(HttpClient.token) - 后续所有业务接口自动携带token,无需每个用例重复传参
- 链路场景:创建订单返回
orderId,存入夹具变量,查询/取消订单直接读取
代码示例(test_login.py)
python
import pytest
from common.http_client import HttpClient
from common.assert_util import assert_code_success
def test_login():
# 发送登录请求
req_data = {"username": "test01", "password": "123456"}
res = HttpClient.send_request("POST", "/login", json=req_data)
# 断言登录成功
assert_code_success(res)
# 提取token,全局共享
HttpClient.token = res["data"]["token"]
# 提取用户ID,存入pytest全局夹具
pytest.user_id = res["data"]["userId"]
3. 数据驱动 DDT:@pytest.mark.parametrize + yaml/csv
作用:一套接口批量执行多组正向/边界/异常参数,减少重复用例代码
方式1:YAML文件读取参数(推荐,可读性高)
data/login_data.yaml
yaml
cases:
- name: 正常账号登录
username: test01
pwd: 123456
expect_code: 200
- name: 密码错误
username: test01
pwd: 666666
expect_code: 400
用例读取yaml批量执行:
python
import yaml
import pytest
from common.http_client import HttpClient
# 读取yaml数据
with open("./data/login_data.yaml", "r", encoding="utf-8") as f:
login_cases = yaml.safe_load(f)["cases"]
@pytest.mark.parametrize("case", login_cases)
def test_login_param(case):
res = HttpClient.send_request("POST", "/login", json={"username":case["username"], "password":case["pwd"]})
assert res["code"] == case["expect_code"]
方式2:CSV批量数据(大批量造数场景)
搭配pandas读取csv,实现上千条账号参数化执行。
4. 多层断言 + 数据库落库校验
(1)多层JSON通用断言 common/assert_util.py
支持校验顶层code、嵌套字段、数组长度、字段非空
python
def assert_code_success(response):
"""校验业务码200"""
assert response["code"] == 200, f"业务失败:{response['msg']}"
def assert_json_field(res, json_path, expect_val):
"""多层字段断言,如$.data.user.name"""
import jsonpath
val = jsonpath.jsonpath(res, json_path)[0]
assert val == expect_val
(2)数据库落库校验(接口自动化核心强校验)
场景:调用创建订单接口后,查询MySQL订单表,校验订单号、金额、状态是否正确落库
python
from common.db_util import DB
def test_create_order():
# 1. 调用创建订单接口
req = {"goodsId": 1001, "num": 2}
res = HttpClient.send_request("POST", "/order/create", json=req)
order_id = res["data"]["orderId"]
# 2. 查询数据库订单
sql = f"select order_id, amount, status from t_order where order_id='{order_id}'"
db_data = DB.query_one(sql)
# 3. 数据库断言
assert db_data["status"] == 1 # 状态1=待支付
assert db_data["amount"] == 199.00
5. 完整日志记录 log_util.py
日志要求:
- 区分日志等级:INFO正常报文、ERROR失败堆栈
- 完整打印请求URL、请求头、入参、响应码、返回JSON
- 日志按日期分文件保存,Allure报告可嵌入日志详情
python
import logging
from config.setting import LOG_PATH
def get_logger():
logger = logging.getLogger("api_auto")
logger.setLevel(logging.INFO)
# 文件输出+控制台输出
file_handler = logging.FileHandler(LOG_PATH, encoding="utf-8")
console_handler = logging.StreamHandler()
fmt = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
file_handler.setFormatter(fmt)
logger.addHandler(file_handler)
logger.addHandler(console_handler)
return logger
logger = get_logger()
三、持续集成 CI/CD(Jenkins + Allure)
1. 整体流程
代码提交Git → Jenkins自动拉取代码 → 安装Python依赖 → 执行pytest自动化用例 → 生成Allure原始结果 → 渲染HTML报告 → 归档报告 + 邮件推送测试结果
2. Jenkins Shell执行脚本
bash
# 1. 安装依赖
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
# 2. 清空历史报告
rm -rf reports/raw reports/html
# 3. 执行pytest,生成allure原始数据
pytest testcases/ --alluredir=reports/raw -s
# 4. 渲染allure可视化报告
allure generate reports/raw -o reports/html --clean
# 5. 判断用例失败,让Jenkins构建失败
if [ $? -ne 0 ];then
echo "自动化用例存在失败!"
exit 1
fi
3. 配套配置
- Jenkins插件:Allure Report、Email Extension
- 构建后操作:
- 归档reports/html报告
- 发送邮件:附件html报告,区分成功/失败邮件模板
- 触发方式:
- 代码提交触发(GitLab WebHook)
- 定时构建:每日凌晨2点全量回归核心链路
四、用例管理规范
1. 自动化用例与手工用例关联
- 自动化用例只覆盖核心业务流程(登录、下单、支付、查询),不覆盖极端低频异常;
- 每个自动化用例添加注释,关联测试管理平台用例ID(如
#TC001 正常下单流程); - 迭代更新:需求变更同步修改自动化脚本,保证和手工用例同步。
2. 环境清理与造数策略
(1)前置造数(conftest夹具)
@pytest.fixture(scope="module", autouse=True)
模块执行前自动创建测试账号、测试商品数据,保证用例有数据可执行。
(2)后置数据清理
- 模块执行完成,删除本次自动化生成的订单、用户脏数据;
- 避免数据库持续堆积测试数据,导致接口查询越来越慢;
- 生产隔离:自动化单独一套性能/测试库,禁止操作线上库。
3. 分层执行策略
- 冒烟用例:仅核心链路,代码提交快速执行(5分钟内)
- 全量回归:定时任务执行所有自动化用例(夜间执行)
- 模块分组:通过
@pytest.mark.order标记,Jenkins可单独执行订单模块。
五、面试高频考点总结
- 为什么分层设计common/config/data/testcases?
解耦、复用、易维护,修改环境地址只改yaml,修改请求逻辑只改http_client。 - pytest如何实现接口关联?
全局静态变量、夹具fixture共享参数,登录提取token存入全局请求类,下游自动携带。 - 数据驱动实现方式?
@pytest.mark.parametrize + yaml/csv,多组参数批量执行,减少重复代码。 - 自动化和手工测试区别?
自动化擅长重复回归、核心链路;手工擅长复杂交互、UI、低频异常场景。 - CI集成流程?
Git触发Jenkins→拉代码→安装依赖→pytest执行→生成Allure报告→邮件通知。