在自动化测试、接口调试等场景中,requests 是 Python 中非常常用的 HTTP 客户端库。为了提高代码的可维护性与复用性,我们通常会对 requests 进行二次封装。本文将详细介绍如何对 requests 库进行封装,实现一个支持变量替换、日志记录、Allure 报告集成等功能的 HTTP 请求类。
🧾 一、项目背景
在实际开发和测试过程中,频繁地使用原始 requests.get()、requests.post() 等方法容易导致代码重复、逻辑混乱。通过封装 requests,我们可以统一请求入口、自动处理变量、记录日志、生成测试报告等,提升整体开发效率和代码质量。
🛠️ 二、封装目标
本次封装的目标包括:
- 支持多种 HTTP 方法(GET、POST、PUT、DELETE 等)
- 支持变量替换(如 ${username} 替换为缓存中的值)
- 自动记录请求日志
- 集成 Allure 报告展示请求详情
- 支持合并字典参数(headers、timeout 等)
📦 三、依赖模块介绍
import typing as t
import allure
import urllib3
from requests import Session, Response
from common.cache import cache
from common.json import json, loads, dumps
from common.regular import sub_var, findalls
from utils.logger import logger
- typing:用于类型注解,增强代码可读性和 IDE 智能提示。
- allure:用于在测试报告中动态添加请求信息。
- urllib3:禁用 SSL 警告。
- requests.Session:保持会话状态,提高请求效率。
- common.cache:缓存模块,用于变量替换。
- common.regular:正则处理模块,用于提取和替换变量。
- utils.logger:日志模块,记录请求过程。
🔧 四、核心类设计 —— HttpRequest
该类继承自 requests.Session,实现了请求的统一处理流程。
1. 初始化方法 __init__
def __init__(self, *args: t.Union[t.Set, t.List], **kwargs: t.Dict[t.Text, t.Any]):
super(HttpRequest, self).__init__()
self.exception = kwargs.get("exception", Exception)
- 继承 Session 实现会话保持。
- 可选传入异常类,默认为 Exception。
2. 发送请求方法 send_request
这是整个封装的核心方法,负责处理请求的构建、发送及结果处理。
参数解析
method = kwargs.get('method', 'GET').upper()
baseurl = cache.get('baseurl', '')
url = baseurl + kwargs.get('route', '')
- 从 kwargs 中获取请求方法、路由路径,并拼接完整 URL。
- 使用 cache 获取基础地址,便于环境切换。
变量替换
replace_variables(kwargs, cache)
- 调用 replace_variables 函数递归替换所有变量占位符,例如 ${token} 替换为缓存中的 token 值。(replace_variables 方法下方有写)
构造请求参数
request_data = self.mergedict(
kwargs.get('RequestData', {}),
headers=kwargs.get('headers', None)
)
- 合并请求体和头部信息,确保结构统一。
JSON 格式化数据
if 'data' in kwargs:
request_data['json'] = kwargs['data']
request_data.pop('data', None)
- 如果传入了 data 字段,则将其转换为 json 格式发送。
发送请求
response = self.dispatch(method, url, **request_data)
-
调用 dispatch 分发具体请求方法。
Allure 报告记录
# Allure 报告描述
description_html = f"""
<font color=red>请求方法:</font>{method}<br/>
<font color=red>请求地址:</font>{url}<br/>
<font color=red>请求头:</font>{str(response.headers)}<br/>
<font color=red>请求参数:</font>{json.dumps(kwargs, ensure_ascii=False)}<br/>
<font color=red>响应状态码:</font>{str(response.status_code)}<br/>
<font color=red>响应时间:</font>{str(response.elapsed.total_seconds())}<br/>
"""
allure.dynamic.description_html(description_html)
-
将请求详细信息写入 Allure 测试报告,便于排查问题。
异常捕获
except self.exception as e:
logger.exception(f"请求发送失败: {str(e)}")
raise e
3. 请求分发方法 dispatch
def dispatch(self, method: t.Text, *args: t.Union[t.List, t.Tuple], **kwargs: t.Dict) -> Response:
handler = getattr(self, method.lower())
return handler(*args, **kwargs)
- 根据请求方法名动态调用对应的 get、post 等方法。
4. 字典合并方法 mergedict
@staticmethod
def mergedict(data: t.Dict, **kwargs: t.Dict) -> t.Dict:
result = data.copy()
for key, value in kwargs.items():
if key in ['headers', 'timeout']:
result[key] = value
return result
- 合并额外的关键字参数到请求数据中,如 headers 和 timeout。
🔁 五、变量替换函数 replace_variables
def replace_variables(data, cache):
if isinstance(data, dict):
for key, value in data.items():
if isinstance(value, str):
data[key] = sub_var(findalls(value), value, cache)
elif isinstance(value, dict):
replace_variables(value, cache)
elif isinstance(value, list):
for i, item in enumerate(value):
if isinstance(item, str):
value[i] = sub_var(findalls(item), item, cache)
elif isinstance(item, dict):
replace_variables(item, cache)
- 递归遍历字典和列表,替换字符串中的变量占位符。
🧪 六、示例演示
if __name__ == '__main__':
http_request = HttpRequest()
response = http_request.send_request(
method='GET',
route='/api/data',
RequestData={'param1': 'value1'}
)
print(response.status_code)
print(response.text)
- 运行后会在控制台看到详细的请求日志,并在 Allure 报告中查看完整的请求信息。
Allure 报告示例:
✅ 七、总结
通过对 requests 的封装,我们实现了如下功能:
- 多种 HTTP 方法支持
- 动态变量替换
- 日志记录
- Allure 报告集成
- 参数自动合并处理
这种封装方式不仅提高了代码的复用性和可维护性,也大大提升了测试脚本的健壮性和可读性。
📌 其余参考
1. 安装依赖包
pip install requests allure-python-commons python-dotenv
2. 缓存模块参考(common/cache.py)
class Cache:
def __init__(self):
self._store = {}
def get(self, key, default=None):
return self._store.get(key, default)
def set(self, key, value):
self._store[key] = value
cache = Cache()
3. 正则模块参考(common/regular.py)
import re
def findalls(text):
return re.findall(r'\$\{(.*?)\}', text)
def sub_var(matches, text, cache):
for var in matches:
value = cache.get(var, '')
text = text.replace('${%s}' % var, str(value))
return text