如何用AI工具开发一个轻量化CRM系统(七):AI生成pytest测试脚本

要实现根据Flask接口文档自动生成测试脚本、自动执行多次并汇总结果 ,可以通过解析Swagger文档 +动态生成pytest测试用例 +测试结果汇总的流程完成。以下是完整的Python实现方案:

一、环境准备

  1. 安装依赖库:

    bash 复制代码
    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)。我们需要先获取该文档,解析出所有接口的信息(路径、方法、参数、预期响应)。

python 复制代码
import requests
from typing import Dict, List, Any

def 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. 生成测试用例

根据解析出的接口信息,生成覆盖正常流、异常流、边界条件的测试用例。例如,登录接口的测试用例包括:正常登录、错误用户名、错误密码、缺少参数等。

python 复制代码
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的动态测试生成能力,为每个测试用例生成独立的测试函数,自动发送请求并验证响应。

python 复制代码
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报告。

python 复制代码
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. 动态注册测试函数到pytest
        for 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)

三、使用说明

  1. 启动Flask应用 :确保你的Flask应用运行在http://localhost:8000,并集成了flasgger(可通过/swagger.json访问Swagger文档)。

  2. 运行测试脚本 :执行上述Python脚本:

    bash 复制代码
    python test_crm_api.py
  3. 查看结果

    • 命令行会输出详细的测试结果(通过/失败/错误);
    • 生成report.html文件,打开后可查看测试用例详情失败原因汇总统计(通过率、失败数等)。

四、扩展功能

1. 自动执行多次测试

通过pytest的--count参数指定执行次数(例如执行5次):

bash 复制代码
pytest.main([
    __file__,
    "-v",
    "--html=report.html",
    "--count=5"  # 执行5次测试
])
2. 更灵活的测试数据管理

若测试数据需要复用或参数化,可以使用pytest的@pytest.mark.parametrize装饰器。例如,登录接口的多组用户名/密码:

python 复制代码
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 401
    assert expected_message in response.json()["message"]
3. 集成CI/CD

可以将测试脚本集成到CI/CD pipeline(如GitHub Actions、Jenkins),每次代码提交后自动执行测试并生成报告。

总结

该方案通过解析Swagger文档 实现测试用例的自动生成,通过pytest动态测试 实现自动执行,通过HTML报告实现结果汇总。完全符合"根据接口文档生成测试脚本、自动执行多次、汇总结果"的需求,且支持灵活扩展(如参数化测试、CI/CD集成)。

相关推荐
慌糖15 小时前
自动化接口框架搭建分享-pytest第三部分
运维·自动化·pytest
Script kid15 小时前
Pytest框架速成
数据库·pytest
小熊出擊15 小时前
[pytest] 一文掌握 fixture 的作用域(scope)机制
python·功能测试·单元测试·自动化·pytest
小熊出擊1 天前
[pytest] autouse 参数:自动使用fixture
python·测试工具·单元测试·自动化·pytest
菠萝吹雪ing3 天前
pytest中的assert断言
python·pytest
天才测试猿4 天前
Python常用自动化测试框架—Pytest详解
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·pytest
慌糖4 天前
自动化接口框架搭建分享-pytest第二部分
运维·自动化·pytest
know__ledge4 天前
Pytest+requests进行接口自动化测试6.0(Jenkins)
elasticsearch·jenkins·pytest
慌糖6 天前
自动化接口框架搭建分享-pytest
运维·自动化·pytest