当前位置: 首页 > 测试知识 > 接口自动化测试框架设计-基于Requests与Allure测试报告
接口自动化测试框架设计-基于Requests与Allure测试报告
2026-07-30 作者cwb 浏览次数21

设计一个基于Requests和Allure的接口自动化测试框架,要解决三个问题:易编写、好维护、报告清晰。


一、框架选型

Requests:简洁的 HTTP 客户端,支持 Session 保持、SSL 校验、连接池,学习成本极低。

Allure:测试报告框架,可生成清晰直观的 HTML 报告,支持步骤、附件、分级标签,与 Pytest 原生集成。

Pytest:用例组织与运行引擎,提供 fixture、参数化、标记、钩子等能力。

整体风格:分层解耦 + API Object 模式 + 数据驱动。


二、整体架构分层

从上到下共分为四层:


测试用例层

基于Pytest编写的测试文件,使用 @allure.step、@allure.feature 等装饰器描述业务,直接调用接口对象层提供的方法。


接口对象层(API Object)

将系统接口按模块封装成类(如UserAPI、OrderAPI),对外暴露业务动作(login、create_order),内部统一使用基础工具层的请求客户端发送HTTP请求。


基础工具层(Utils)

提供通用能力:Requests Session 封装(自动处理Token、日志、重试、超时)、日志模块、断言封装、数据库辅助等。


数据与配置层

存放多环境配置文件(config.yaml)、测试数据文件(YAML/CSV)以及环境变量,供各层读取使用。

三、目录结构说明

项目根目录为api-test-framework/,主要子目录和文件如下:


config/

存放配置文件,包含config.yaml(多环境全局配置)和env.yaml(环境变量覆盖)。


data/

存放测试数据,例如 login_data.yaml、order_data.csv 等。


apis/

接口对象层代码,包含 __init__.py、base_api.py(公共请求基类)、user_api.py、order_api.py 等模块。


utils/

工具层代码,包含 __init__.py、request_client.py(Session 封装)、logger.py、assertion.py、db_helper.py。


testcases/

测试用例目录,包含 conftest.py(全局 fixture)、test_login.py、test_order.py 等测试文件。


reports/

用于存放生成的 Allure 原始结果和 HTML 报告。


pytest.ini

Pytest 配置文件。


requirements.txt

项目依赖列表。


run.py

统一运行入口脚本。


四、模块实现


1. 配置管理(config/config.yaml)


yaml

env: test

test:

  base_url: "https://test-api.example.com"

  timeout: 10

  db:

    host: "127.0.0.1"

    user: "tester"

    password: "secret"

    database: "testdb"

prod:

  base_url: "https://api.example.com"

  timeout: 5


加载配置工具(utils/config_reader.py)使用 pyyaml 读取并合并环境变量。


2. 日志模块(utils/logger.py)


python

import logging

import sys

from pathlib import Path


def get_logger(name=__name__):

    logger = logging.getLogger(name)

    logger.setLevel(logging.DEBUG)

    if not logger.handlers:

        handler = logging.StreamHandler(sys.stdout)

        fmt = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')

        handler.setFormatter(fmt)

        logger.addHandler(handler)

    return logger


3. 请求客户端封装(utils/request_client.py)

封装 requests.Session,实现自动挂载 Token、SSL 忽略或证书、连接重试、请求/响应日志记录。


python

import requests

from requests.adapters import HTTPAdapter

from urllib3.util.retry import Retry

from utils.logger import get_logger


logger = get_logger(__name__)


class RequestClient:

    def __init__(self, base_url, timeout=10):

        self.base_url = base_url.rstrip('/')

        self.timeout = timeout

        self.session = requests.Session()

        retries = Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503])

        self.session.mount('http://', HTTPAdapter(max_retries=retries))

        self.session.mount('https://', HTTPAdapter(max_retries=retries))

        self.session.headers.update({'Content-Type': 'application/json'})


    def _log_request(self, method, url, **kwargs):

        logger.info(f"Request: {method.upper()} {url} | params={kwargs.get('params')} | json={kwargs.get('json')}")


    def _log_response(self, response):

        logger.info(f"Response: {response.status_code} | time={response.elapsed.total_seconds():.3f}s | body={response.text[:500]}")


    def send_request(self, method, path, **kwargs):

        url = f"{self.base_url}{path}"

        kwargs.setdefault('timeout', self.timeout)

        self._log_request(method, url, **kwargs)

        try:

            resp = self.session.request(method, url, **kwargs)

            self._log_response(resp)

            return resp

        except Exception as e:

            logger.error(f"Request failed: {e}")

            raise


4. 通用断言封装(utils/assertion.py)


python

import jsonpath

from jsonschema import validate


def assert_status_code(response, expected_code):

    assert response.status_code == expected_code, \

        f"Expected {expected_code}, got {response.status_code}, body: {response.text}"


def assert_json_value(response, expr, expected_value):

    actual = jsonpath.jsonpath(response.json(), expr)

    assert actual, f"JsonPath '{expr}' not found"

    assert actual[0] == expected_value, f"Expected {expected_value}, got {actual[0]}"


5. API Object 基类(apis/base_api.py)


python

class BaseAPI:

    def __init__(self, client: 'RequestClient'):

        self.client = client


6. 具体接口封装(apis/user_api.py)


python

import allure

from apis.base_api import BaseAPI


class UserAPI(BaseAPI):

    @allure.step("登录接口")

    def login(self, username, password):

        path = "/api/v1/login"

        payload = {"username": username, "password": password}

        return self.client.send_request("POST", path, json=payload)


    @allure.step("获取用户信息")

    def get_user_info(self, token):

        headers = {"Authorization": f"Bearer {token}"}

        return self.client.send_request("GET", "/api/v1/user/me", headers=headers)


7. 全局 Fixture(testcases/conftest.py)


python

import pytest

import allure

from utils.request_client import RequestClient

from apis.user_api import UserAPI

from utils.config_reader import load_config


@pytest.fixture(scope="session")

def config():

    return load_config("config/config.yaml")


@pytest.fixture(scope="session")

def client(config):

    env = config['env']

    base_url = config[env]['base_url']

    return RequestClient(base_url, timeout=config[env]['timeout'])


@pytest.fixture(scope="session")

def admin_token(client, config):

    user_api = UserAPI(client)

    resp = user_api.login("admin", "admin123")

    assert resp.status_code == 200

    token = resp.json()["data"]["token"]

    client.session.headers.update({"Authorization": f"Bearer {token}"})

    with allure.step("获取管理员Token"):

        allure.attach(str(token), "Admin Token")

    return token


@pytest.fixture

def user_api(client):

    return UserAPI(client)



8. 测试用例编写(testcases/test_login.py)

python

import allure

import pytest


@allure.feature("用户模块")

class TestLogin:


    @allure.story("登录成功")

    @allure.severity(allure.severity_level.BLOCKER)

    @pytest.mark.parametrize("username,password", [

        ("admin", "admin123"),

        ("user1", "pass1")

    ])

    def test_login_success(self, user_api, username, password):

        resp = user_api.login(username, password)

        with allure.step("校验状态码200"):

            assert resp.status_code == 200

        with allure.step("校验返回token不为空"):

            assert resp.json()["data"]["token"] != ""


    @allure.story("登录失败-密码错误")

    def test_login_fail(self, user_api):

        resp = user_api.login("admin", "wrong_pass")

        with allure.step("校验状态码401"):

            assert resp.status_code == 401

        with allure.step("校验错误信息"):

            assert "invalid" in resp.json()["message"]


9. Allure配置运行

安装依赖:


bash

pip install requests pyyaml pytest allure-pytest jsonpath-ng jsonschema

# 还需下载 allure 命令行工具并添加到 PATH


配置 pytest.ini:


ini

[pytest]

addopts = -v -s --alluredir=reports/allure_raw

testpaths = testcases


运行并生成报告:


bash

pytest

allure generate reports/allure_raw -o reports/allure_html --clean

allure open reports/allure_html


10. 统一运行入口(run.py)


python

import pytest

import os

import sys


if __name__ == "__main__":

    exit_code = pytest.main([

        "-v", "-s",

        "--alluredir=reports/allure_raw",

        "testcases"

    ])

    os.system("allure generate reports/allure_raw -o reports/allure_html --clean")

    sys.exit(exit_code)


五、扩展设计要点

数据驱动增强

可将测试数据从 YAML/Excel 读取并参数化,例如:


python

def load_yaml_data(file_path):

    import yaml

    with open(file_path, encoding='utf-8') as f:

        return yaml.safe_load(f)


@pytest.mark.parametrize("case", load_yaml_data("data/login_data.yaml"))

def test_login_with_data(self, user_api, case):

    resp = user_api.login(case["username"], case["password"])

    assert resp.status_code == case["expected_status"]


多环境切换

通过命令行参数 --env=prod 传入,conftest动态加载配置。


接口间的依赖处理

避免用例强依赖,使用fixture创建前置数据,并在yield后清理;或利用依赖注入共享资源。


数据库与Mock

数据库工具:在utils中封装pymysql/sqlalchemy,在fixture中提供数据准备。


Mock服务:使用responses库或WireMock模拟第三方依赖,在fixture中启动与销毁。


Allure进阶

步骤中截图/附件:allure.attach(response.text, "响应", allure.attachment_type.JSON)

添加环境信息:创建 environment.properties 放到 allure 结果目录。

使用 @allure.tag、@allure.epic、@allure.link 丰富报告元数据。


这套框架的优势:

高内聚低耦合:请求、业务、数据、用例分离,修改基类不影响用例。

复用性强:API Object 层可被任何用例调用,减少重复代码。

报告即文档:Allure 的 Feature/Story/Step 与业务语义对应,非技术人员也能看懂。

易于维护:新增接口只需实现 API 类和用例,配置与数据独立管理。


文章标签: 自动化测试 接口性能测试 测试报告
咨询软件测试