`pytest + YAML + Allure` 的接口自动化测试框架是业界广泛使用的组合
pytest + YAML + Allure 的接口自动化测试框架是业界广泛使用的组合,其核心优势在于:用 YAML 管理测试用例(简洁易维护)、用 pytest 驱动执行(灵活强大)、用 Allure 生成可视化报告(美观且支持丰富细节)。以下是框架的设计思路、核心模块及实现步骤:
一、框架核心设计理念
- 分层设计:将用例、配置、工具、报告等模块解耦,便于维护和扩展。
- 数据与逻辑分离:测试数据(请求参数、预期结果等)用 YAML 存储,测试逻辑(发送请求、断言等)用 Python 实现。
- 可扩展性:支持环境配置切换、接口依赖处理、全局前置/后置操作等。
二、框架目录结构
推荐的目录结构如下(按功能分层):
api_auto_test/
├── config/ # 配置文件目录
│ ├── env.yaml # 环境配置(如测试/生产环境的域名、headers等)
│ └── settings.py # 全局常量(如报告路径、超时时间等)
├── data/ # 测试数据目录
│ └── api_cases/ # YAML格式的接口测试用例
│ ├── login.yaml
│ └── user.yaml
├── libs/ # 工具库/公共方法
│ ├── request.py # 封装HTTP请求(基于requests)
│ ├── yaml_util.py # YAML文件读写工具
│ └── extractor.py # 响应结果提取工具(用于接口依赖)
├── tests/ # 测试用例执行层
│ ├── conftest.py # pytest fixtures(前置/后置、环境初始化等)
│ ├── test_login.py # 登录接口测试用例(调用YAML数据)
│ └── test_user.py # 用户相关接口测试用例
├── reports/ # 测试报告目录(Allure生成)
├── logs/ # 日志目录
├── requirements.txt # 依赖库清单
└── run.py # 执行入口(触发pytest运行)
三、核心模块实现
1. 配置模块(config/)
- env.yaml:存储多环境配置,支持切换环境(如
test/prod):# 环境配置 test:base_url: "https://test-api.example.com"headers:Content-Type: "application/json" prod:base_url: "https://api.example.com"headers:Content-Type: "application/json" - settings.py:定义全局变量(如默认环境、报告路径):
import os BASE_DIR = os.path.dirname(os.path.abspath(__file__)) DEFAULT_ENV = "test" # 默认使用测试环境 ALLURE_REPORT_DIR = os.path.join(BASE_DIR, "../reports/allure-results")
2. 工具库(libs/)
-
request.py:封装 HTTP 请求(get/post/put/delete),自动关联环境配置:
import requests from config.settings import DEFAULT_ENV from libs.yaml_util import read_yamlclass RequestHandler:def __init__(self):self.env = read_yaml("config/env.yaml")[DEFAULT_ENV]self.base_url = self.env["base_url"]self.headers = self.env["headers"]def send_request(self, method, url, **kwargs):"""发送请求:拼接base_url,处理headers和参数"""full_url = f"{self.base_url}{url}"# 合并默认headers和用例中的headersif "headers" in kwargs:self.headers.update(kwargs.pop("headers"))# 发送请求response = requests.request(method=method,url=full_url,headers=self.headers,** kwargs)return response.json() # 返回JSON响应 -
yaml_util.py:封装 YAML 读写方法(用于读取用例和配置):
import yaml import os from config.settings import BASE_DIRdef read_yaml(file_path):"""读取YAML文件,返回字典"""full_path = os.path.join(BASE_DIR, file_path)with open(full_path, "r", encoding="utf-8") as f:return yaml.safe_load(f)def write_yaml(file_path, data):"""写入数据到YAML文件"""full_path = os.path.join(BASE_DIR, file_path)with open(full_path, "w", encoding="utf-8") as f:yaml.safe_dump(data, f, allow_unicode=True) -
extractor.py:提取响应中的字段(用于接口依赖,如用登录返回的 token 作为后续接口的参数):
def extract_data(response, extract_expr):"""从响应中提取数据,支持简单表达式(如 'token'、'user.id')"""data = responsefor key in extract_expr.split("."):if isinstance(data, dict) and key in data:data = data[key]else:return None # 提取失败返回Nonereturn data
3. 测试用例(data/ 和 tests/)
-
YAML 用例(data/api_cases/login.yaml):存储接口信息、参数、预期结果等:
- case_id: 1case_name: 正常登录method: posturl: /loginjson:username: "test_user"password: "123456"extract: # 需要提取的响应字段(如token)token: "data.token"validate: # 断言规则(支持相等、包含等)- eq: ["status_code", 200]- eq: ["data.code", 0]- contains: ["data.msg", "success"]- case_id: 2case_name: 密码错误登录method: posturl: /loginjson:username: "test_user"password: "wrong_pwd"validate:- eq: ["status_code", 200]- eq: ["data.code", 1001] -
pytest 测试脚本(tests/test_login.py):读取 YAML 用例并执行:
import pytest from libs.request import RequestHandler from libs.yaml_util import read_yaml from libs.extractor import extract_data from pytest_allure import allure# 读取YAML用例 test_cases = read_yaml("data/api_cases/login.yaml")@pytest.mark.parametrize("case", test_cases) def test_login(case, request_handler, extractor_store):"""登录接口测试"""with allure.step(f"执行用例:{case['case_name']}"):# 发送请求response = request_handler.send_request(method=case["method"],url=case["url"],json=case.get("json"))# 提取响应字段(存入全局变量,供其他接口使用)if "extract" in case:for key, expr in case["extract"].items():extractor_store[key] = extract_data(response, expr)# 执行断言for validate in case["validate"]:rule, [path, expected] = next(iter(validate.items()))actual = extract_data(response, path)if rule == "eq":assert actual == expected, f"预期{expected},实际{actual}"elif rule == "contains":assert expected in actual, f"{actual}不包含{expected}"
4. 前置/后置操作(conftest.py)
使用 pytest 的 fixture 定义全局前置(如初始化请求对象)、后置(如清理数据)操作:
import pytest
from libs.request import RequestHandler@pytest.fixture(scope="session")
def request_handler():"""全局请求对象(会话级别)"""return RequestHandler()@pytest.fixture(scope="session")
def extractor_store():"""存储提取的参数(供接口依赖使用)"""return {}
5. 执行入口(run.py)
通过 pytest 执行测试,并生成 Allure 报告:
import os
import pytest
from config.settings import ALLURE_REPORT_DIRif __name__ == "__main__":# 清除旧报告,执行测试并生成Allure结果os.system(f"rm -rf {ALLURE_REPORT_DIR}/*")pytest.main(["tests/",f"--alluredir={ALLURE_REPORT_DIR}","-v", # 显示详细日志"-s" # 显示打印信息])# 生成HTML报告(需提前安装allure命令行工具)os.system(f"allure generate {ALLURE_REPORT_DIR} -o reports/html --clean")
四、Allure 报告增强
通过 @allure 装饰器为报告添加更多细节(如用例描述、步骤、标签):
@allure.epic("用户模块")
@allure.feature("登录接口")
class TestLogin:@allure.story("正常登录场景")@allure.title("{case['case_name']}") # 用例标题@allure.severity(allure.severity_level.CRITICAL) # 优先级@pytest.mark.parametrize("case", test_cases)def test_login(self, case):# ... 测试逻辑 ...
五、依赖库安装(requirements.txt)
pytest==7.4.0
requests==2.31.0
PyYAML==6.0.1
allure-pytest==2.13.2
六、框架优势与扩展方向
-
优势:
- 用例可视化(YAML 易读,非开发也能维护)。
- 支持参数化、接口依赖、多环境切换。
- Allure 报告支持趋势分析、失败截图、日志嵌入等。
-
扩展方向:
- 集成数据库操作(验证接口对数据的影响)。
- 添加接口加密/解密处理(如签名、token 刷新)。
- 对接 CI/CD(如 Jenkins,实现定时执行)。
- 增加日志模块(记录请求/响应详情,便于排查问题)。
通过这套框架,可快速搭建稳定、可维护的接口自动化体系,尤其适合中小型项目或需要快速落地的团队。
