如何用AI工具开发一个轻量化CRM系统(七):AI生成pytest测试脚本
要实现根据Flask接口文档自动生成测试脚本、自动执行多次并汇总结果,可以通过解析Swagger文档+动态生成pytest测试用例+测试结果汇总的流程完成。以下是完整的Python实现方案:
一、环境准备
- 安装依赖库:
pip install requests pytest pytest-html flasgger
requests
:发送HTTP请求;pytest
:测试框架,支持自动发现和执行测试;pytest-html
:生成HTML测试报告;flasgger
:Flask的Swagger文档生成库(确保你的Flask应用已集成,用于提供结构化的Swagger JSON)。
二、核心逻辑实现
1. 获取并解析Swagger文档
Flask应用通常通过/swagger.json
提供结构化的Swagger文档(需集成flasgger
)。我们需要先获取该文档,解析出所有接口的信息(路径、方法、参数、预期响应)。
import requests
from typing import Dict, List, Anydef get_swagger_doc(swagger_url: str) -> Dict[str, Any]:"""获取Swagger JSON文档"""response = requests.get(swagger_url)response.raise_for_status() # 确保请求成功return response.json()def parse_swagger_interfaces(swagger_doc: Dict[str, Any]) -> List[Dict[str, Any]]:"""解析Swagger文档,提取接口信息(路径、方法、参数、响应)"""interfaces = []paths = swagger_doc.get("paths", {})for path, methods in paths.items():for method, details in methods.items():# 仅处理GET/POST/PUT/DELETE方法if method.lower() in ["get", "post", "put", "delete"]:interface = {"path": path,"method": method.upper(),"parameters": details.get("parameters", []), # 接口参数(查询/请求体)"responses": details.get("responses", {}) # 预期响应}interfaces.append(interface)return interfaces
2. 生成测试用例
根据解析出的接口信息,生成覆盖正常流、异常流、边界条件的测试用例。例如,登录接口的测试用例包括:正常登录、错误用户名、错误密码、缺少参数等。
def generate_test_cases(interfaces: List[Dict[str, Any]]) -> List[Dict[str, Any]]:"""根据接口信息生成测试用例"""test_cases = []for interface in interfaces:path = interface["path"]method = interface["method"]# 1. 登录接口(/login,POST)if path == "/login" and method == "POST":test_cases.extend([{"name": "login_success", # 测试用例名称"request": {"json": {"username": "admin", "password": "password123"}},"expected": {"status_code": 200, "json": {"access_token": str, "message": "登录成功"}}},{"name": "login_wrong_username","request": {"json": {"username": "nonexistent", "password": "password123"}},"expected": {"status_code": 401, "json": {"message": "用户名或密码错误"}}},{"name": "login_missing_username","request": {"json": {"password": "password123"}},"expected": {"status_code": 400, "json": {"message": "缺少必填字段: username"}}}])# 2. 客户列表接口(/crm/customers,GET)elif path == "/crm/customers" and method == "GET":test_cases.extend([{"name": "get_customers_success","request": {},"expected": {"status_code": 200, "json": {"customers": list, "pagination": dict}}},{"name": "get_customers_unauthorized","request": {},"expected": {"status_code": 401, "json": {"message": "缺少访问令牌"}}}])# 3. 创建客户接口(/crm/customers,POST)elif path == "/crm/customers" and method == "POST":test_cases.extend([{"name": "create_customer_success","request": {"json": {"name": "李四", "email": "lisi@example.com", "phone": "13900139000"}},"expected": {"status_code": 201, "json": {"id": int, "name": "李四", "email": "lisi@example.com", "message": "客户创建成功"}}},{"name": "create_customer_missing_name","request": {"json": {"email": "lisi@example.com", "phone": "13900139000"}},"expected": {"status_code": 400, "json": {"message": "缺少必填字段: name"}}}])return test_cases
3. 动态生成pytest测试函数
利用pytest的动态测试生成能力,为每个测试用例生成独立的测试函数,自动发送请求并验证响应。
def generate_test_function(test_case: Dict[str, Any]) -> callable:"""为单个测试用例生成pytest测试函数"""def test_func():# 构造请求URL和方法method = test_case["request"].get("method", "POST").upper()path = test_case["path"]url = f"http://localhost:8000{path}" # 替换为你的API地址request_data = test_case["request"]# 发送HTTP请求if method == "POST":response = requests.post(url, json=request_data.get("json", {}))elif method == "GET":response = requests.get(url, params=request_data.get("params", {}))elif method == "PUT":response = requests.put(url, json=request_data.get("json", {}))elif method == "DELETE":response = requests.delete(url, params=request_data.get("params", {}))else:raise ValueError(f"不支持的请求方法: {method}")# 验证1:状态码是否符合预期expected_status = test_case["expected"]["status_code"]assert response.status_code == expected_status, \f"测试用例[{test_case['name']}]失败:预期状态码{expected_status},实际{response.status_code}"# 验证2:响应体结构和类型是否符合预期expected_json = test_case["expected"]["json"]response_json = response.json()for key, expected_type in expected_json.items():assert key in response_json, \f"测试用例[{test_case['name']}]失败:响应缺少字段[{key}]"assert isinstance(response_json[key], expected_type), \f"测试用例[{test_case['name']}]失败:字段[{key}]类型错误(预期{expected_type.__name__},实际{type(response_json[key]).__name__})"return test_func
4. 主程序:注册测试用例并执行
将上述步骤整合,自动生成测试用例、注册测试函数,并通过pytest执行测试,生成HTML报告。
if __name__ == "__main__":# 1. 配置Swagger文档地址(根据你的Flask应用调整)SWAGGER_URL = "http://localhost:8000/swagger.json"try:# 2. 获取并解析Swagger文档swagger_doc = get_swagger_doc(SWAGGER_URL)interfaces = parse_swagger_interfaces(swagger_doc)print(f"✅ 成功解析到 {len(interfaces)} 个接口")# 3. 生成测试用例test_cases = generate_test_cases(interfaces)print(f"✅ 生成 {len(test_cases)} 个测试用例")# 4. 动态注册测试函数到pytestfor test_case in test_cases:test_name = f"test_{test_case['name']}" # pytest测试函数命名规则test_func = generate_test_function(test_case)globals()[test_name] = test_func # 将测试函数加入全局命名空间# 5. 执行测试(生成HTML报告)print("
🚀 开始运行测试...")pytest.main([__file__, # 当前脚本"-v", # 详细模式(显示每个测试用例的结果)"--html=report.html", # 生成HTML报告"--self-contained-html" # 报告包含所有依赖(无需额外文件)])except Exception as e:print(f"❌ 执行失败:{e}")exit(1)
三、使用说明
- 启动Flask应用:确保你的Flask应用运行在
http://localhost:8000
,并集成了flasgger
(可通过/swagger.json
访问Swagger文档)。 - 运行测试脚本:执行上述Python脚本:
python test_crm_api.py
- 查看结果:
- 命令行会输出详细的测试结果(通过/失败/错误);
- 生成
report.html
文件,打开后可查看测试用例详情、失败原因和汇总统计(通过率、失败数等)。
四、扩展功能
1. 自动执行多次测试
通过pytest的--count
参数指定执行次数(例如执行5次):
pytest.main([__file__,"-v","--html=report.html","--count=5" # 执行5次测试
])
2. 更灵活的测试数据管理
若测试数据需要复用或参数化,可以使用pytest的@pytest.mark.parametrize
装饰器。例如,登录接口的多组用户名/密码:
import pytest@pytest.mark.parametrize("username, password, expected_message", [("admin", "password123", "登录成功"),("nonexistent", "password123", "用户名或密码错误"),("admin", "wrongpassword", "用户名或密码错误")
])
def test_login_parametrized(username, password, expected_message):# 发送请求并验证response = requests.post("http://localhost:8000/login", json={"username": username, "password": password})assert response.status_code == 200 if "成功" in expected_message else 401assert expected_message in response.json()["message"]
3. 集成CI/CD
可以将测试脚本集成到CI/CD pipeline(如GitHub Actions、Jenkins),每次代码提交后自动执行测试并生成报告。
总结
该方案通过解析Swagger文档实现测试用例的自动生成,通过pytest动态测试实现自动执行,通过HTML报告实现结果汇总。完全符合“根据接口文档生成测试脚本、自动执行多次、汇总结果”的需求,且支持灵活扩展(如参数化测试、CI/CD集成)。