基于Python + Requests + Unitest + HTMLTestRunner_PY3的接口自动化测试框架

前言:

  2025开年第一篇((#^.^#))。

  此框架是基于Python + Requests + Unitest + HTMLTestRunner_PY3接口自动化测试框架,测试接口和测试数据的维护都是通过代码维护的。

  对于接口的请求URL、请求方式、请求头、请求体以及响应结果的断言都需要自己去做对应的维护。

 

一、执行逻辑介绍

  获取测试Token → 授权测试接口 → 执行测试用例 → 输出测试报告

 

二、代码目录结构介绍

  • case:测试用例
  • config:配置文件(Token、Requests二封)
  • data:接口数据(请求URL、请求方式、请求头、请求体、断言、日志)
  • debug:调试数据
  • framework:三方工具
  • report:测试报告
  • run:运行主文件

 

三、代码介绍

config(config.py):

# -*- coding: UTF-8 -*-
import os
import logging
import requests
from requests.adapters import HTTPAdapter
from urllib3.util import Retry

BASE_URL = os.getenv("BASE_URL", "http://127.0.0.1")
LOGIN_URL = "/lit/login"
LOGIN_USER = {
    "username": os.getenv("LOGIN_USER", "lit"),
    "password": os.getenv("LOGIN_PWD", "lit"),
    "token": os.getenv("LOGIN_TOKEN", "wntoken"),
}

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")

class RequestHandle:
    def __init__(self, base_url: str = BASE_URL, timeout: float = 5.0):
        self.base_url = base_url.rstrip("/")
        self.timeout = timeout
        self.session = requests.Session()
        retry = Retry(
            total=3,
            backoff_factor=0.3,
            status_forcelist=(500, 502, 503, 504),
            allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
        )
        adapter = HTTPAdapter(max_retries=retry)
        self.session.mount("http://", adapter)
        self.session.mount("https://", adapter)

    def request(self, path: str, method: str, **kwargs):
        url = path if path.startswith("http") else f"{self.base_url}{path}"
        try:
            res = self.session.request(method=method, url=url, timeout=self.timeout, verify=False, **kwargs)
            res.raise_for_status()
            return res
        except requests.RequestException as exc:
            logger.error("请求失败: %s %s, err=%s", method, url, exc)
            raise

class TokenMes:
    def __init__(self, client: RequestHandle | None = None):
        self.client = client or RequestHandle()

    def token(self) -> str:
        payload = {
            "username": LOGIN_USER["username"],
            "password": LOGIN_USER["password"],
            "token": LOGIN_USER["token"],
        }
        res = self.client.request(LOGIN_URL, "POST", json=payload)
        data = res.json()
        # 假设 token 在 data["res"]["token"]
        token = data.get("res", {}).get("token")
        if not token:
            raise ValueError(f"未获取到 token,响应: {data}")
        logger.info("Token 获取成功")
        return token

 

data(product_data.py):

# -*- coding: UTF-8 -*-
from config.token_cf import TokenMes, RequestHandle

class ProductManagement:
    def __init__(self):
        self.client = RequestHandle()
        self.auth_token = f"Bearer {TokenMes(self.client).token()}"

    def add_product(self, name="API测试新增产品", desc="产品描述字段", status=1):
        headers = {
            "Authorization": self.auth_token,
            "Content-Type": "application/json",
        }
        body = {
            "product_name": name,
            "description": desc,
            "status": status,
        }
        res = self.client.request("/product", "POST", headers=headers, json=body)
        data = res.json()
        assert data.get("code") == "200", f"预期 code=200, 实际: {data}"
        return data

 

 case(test_product.py):

# -*- coding: UTF-8 -*-
import unittest
from data.product_data import ProductManagement

class ProdList(unittest.TestCase):
    """产品列表"""

    def test_add_product(self):
        """新增产品"""
        data = ProductManagement().add_product()
        # 可根据响应结构进一步校验
        self.assertEqual(data.get("code"), "200")
        self.assertTrue(data.get("res"), "返回结果为空")

 

run.py:

************

 

四、执行结果(报告示例)

 

posted @ 2025-01-13 13:14  莲(LIT)  阅读(78)  评论(0)    收藏  举报