8. 请求封装
8.1. 主函数
def run_main(self, name, url, case_name, header, method, cookies=None, file=None, **kwargs):
"""
接口请求主函数
:param url: 请求地址
:param data: 请求体
:param header: 请求头
:param method: 请求方法
:return: response的json格式
"""
try:
# 收集日志报告信息
logs.info(f"接口名称:{name}")
logs.info(f"接口请求地址:{url}")
logs.info(f"请求方法:{method}")
logs.info(f"测试用例名称:{case_name}")
logs.info(f"请求头:{header}")
logs.info(f"Cookies:")
# 请求参数处理
req_params = json.dumps(kwargs, ensure_ascii=False)
if 'data' in kwargs.keys():
logs.info(f'请求参数:{kwargs}')
elif 'json' in kwargs.keys():
logs.info(f'请求参数:{kwargs}')
elif 'params' in kwargs.keys():
logs.info(f'请求参数:{kwargs}')
except Exception as e:
logs.error(e)
response = self.send_request(method=method, url=url, headers=header, cookies=cookies, files=file, verify=False,
**kwargs)
return response
8.1.1. 代码详解
-
方法签名部分
def run_main(self, name, url, case_name, header, method, cookies=None, file=None, **kwargs):
|------------|----|-----------|------------------------------------------------------------------------------------------------------------------------|
| 参数 | 必填 | 说明 | 示例 |
| self | - | 类实例本身 | - |
| name | ✅ | 接口名称 | "用户登录" |
| url | ✅ | 请求地址 | "http://127.0.0.1:8787/dar/user/login " |
| case_name | ✅ | 测试用例名称 | "TC001_正确登录" |
| header | ✅ | 请求头字典 | {"Content-Type": "application/json"} |
| method | ✅ | HTTP 请求方法 | "POST" / "GET" |
| cookies | ❌ | Cookie 字典 | {"session": "abc123"} |
| file | ❌ | 上传文件 | files 格式对象 |
| **kwargs | ❌ | 其他请求参数 | json={}, data={}, params={} |
-
**kwargs 的灵活性: 动态接收请求参数 (data/json/params)
GET 请求 - 传递 params
run_main(..., params={"page": 1, "size": 10})
POST 请求 - 表单提交
run_main(..., data={"username": "test", "password": "123"})
POST 请求 - JSON 提交
run_main(..., json={"user": {"name": "test"}})
-
日志收集部分
logs.info(f"接口名称:{name}") # 【输出】接口名称:用户登录
logs.info(f"接口请求地址:{url}") # 【输出】接口请求地址:http://127.0.0.1:8787/...
logs.info(f"请求方法:{method}") # 【输出】请求方法:POST
logs.info(f"测试用例名称:{case_name}") # 【输出】测试用例名称:TC001_正确登录
logs.info(f"请求头:{header}") # 【输出】请求头:{"Content-Type": "..."}
logs.info(f"Cookies:") # 【输出】Cookies:(后面会显示具体值)
作用: 在测试报告中记录完整的请求信息,方便问题排查。
req_params = json.dumps(kwargs, ensure_ascii=False)
作用:
-
将 kwargs 字典转为 JSON 字符串
-
ensure_ascii=False:支持中文不乱码
if 'data' in kwargs.keys():
logs.info(f'请求参数:{kwargs}')
elif 'json' in kwargs.keys():
logs.info(f'请求参数:{kwargs}')
elif 'params' in kwargs.keys():
logs.info(f'请求参数:{kwargs}') -
检查 kwargs 中包含哪种类型的请求参数
-
使用 if-elif 结构,因为一次请求只会用一种方式传参
三种传参方式的区别:
|--------|------------------|-----------|-----------------------------------|----------------|
| 参数名 | 支持 HTTP 方法 | 数据位置 | Content-Type 常用类型 | 适用场景 |
| params | GET / POST / ... | URL 查询字符串 | 无需指定 | 接口查询、分页、筛选 |
| data | POST / PUT | 请求体(表单) | application/x-www-form-urlencoded | 传统表单提交、登录、简单参数 |
| json | POST / PUT | 请求体(JSON) | application/json | 接口自动化、前后端分离接口 |
- 发送请求部分
|-----------------|------|-----------------------------|
| 传递的参数 | 来源 | 说明 |
| method=method | 方法参数 | HTTP 方法(POST/GET 等) |
| url=url | 方法参数 | 请求地址 |
| headers=header | 方法参数 | 请求头(注意变量名:header → headers) |
| cookies=cookies | 方法参数 | Cookie 信息 |
| files=file | 方法参数 | 上传文件(注意变量名:file → files) |
| verify=False | 硬编码 | 忽略 HTTPS 证书验证 |
| **kwargs | 可变参数 | 解包传递 data/json/params 等 |
**kwargs 的解包传递
# 假设调用时传入
run_main(..., data={"user_name": "test", "passwd": "123"})
# kwargs 变成
kwargs = {"data": {"user_name": "test", "passwd": "123"}}
# **kwargs 解包后相当于
send_request(..., data={"user_name": "test", "passwd": "123"})
8.2. send_request 方法
基于 requests****库封装的接口请求通用方法 ,主要用于自动化测试(结合pytest)中发送 HTTP 请求、自动处理 Cookie、记录日志、异常捕获,是接口自动化测试的核心工具类方法。
整体功能概述
- 发送任意类型的 HTTP 请求(GET/POST/PUT/DELETE 等)
- 自动提取响应中的 Cookie 并保存,下次请求可复用
- 记录请求日志(Cookie、响应信息)
- 捕获各类请求异常,打印错误日志并终止测试用例
- 持久化存储 Cookie 到 YAML 文件
8.2.1. 代码详解
def send_request(self, **kwargs):
- 定义 :类的成员方法,
self代表类实例本身 - 参数 :
**kwargs可变关键字参数,核心作用 :接收 HTTP 请求的所有参数(url/method/headers/data/json等),让方法支持所有类型的 HTTP 请求
cookie = {}
session = requests.Session()
result = None
cookie = {}:空字典,用于封装最终要传递的 Cookie 请求头session = requests.Session():创建requests会话对象
-
- 核心优势:会话会自动管理 Cookie(保持登录状态),比直接用
requests.get()更稳定
- 核心优势:会话会自动管理 Cookie(保持登录状态),比直接用
result = None:初始化响应结果变量,避免未赋值就返回的报错
try:
result = session.request(**kwargs)
try:异常捕获代码块,包裹核心请求逻辑session.request(**kwargs):发送 HTTP 请求
-
- 动态解包
kwargs参数,等价于直接写session.request(method="GET", url="xxx") - 返回值:接口响应对象(包含状态码、响应体、Cookie、响应头)
- 动态解包
set_cookie = requests.utils.dict_from_cookiejar(result.cookies)
- 功能:将响应中的 CookieJar 格式转为 Python 字典
result.cookies:响应自带的 Cookie,格式是RequestsCookieJar(无法直接使用)dict_from_cookiejar:requests工具方法,专门转换 Cookie 格式
if set_cookie:
cookie['Cookie'] = set_cookie
- 判断:如果响应中存在 Cookie(非空)
- 封装:将 Cookie 字典存入
cookie字典的Cookie键中 - 目的:拼接成HTTP 请求头标准格式,下次请求可直接携带
self.read.write_yaml_data(set_cookie)
logs.info(f"cookie:{cookie}")
self.read.write_yaml_data(set_cookie)
-
- 调用类中封装的 YAML 工具方法,将 Cookie 持久化保存到 YAML 文件
- 作用:跨用例、跨脚本复用 Cookie(保持登录态)
logs.info():打印 INFO 级别的日志,记录 Cookie 内容,方便调试
logs.info(f'接口实际返回信息:{result}')
- 打印接口响应对象日志,包含:状态码、响应头、响应体等,用于排查接口问题
except requests.exceptions.ConnectionError:
logs.error(f'接口连接服务器异常!')
pytest.fail('接口请求异常,可能是request的连接数过多,或者请求速度过快导致程序报错')
- 异常类型:连接异常(服务器无响应、网络不通、域名错误、连接超时)
- 操作:打印 ERROR 日志 + 用
pytest.fail()强制终止测试用例,并给出明确报错原因
except requests.exceptions.HTTPError:
logs.error(f"http异常")
pytest.fail("http请求异常")
- 异常类型:HTTP 协议异常(如 4xx 客户端错误、5xx 服务端错误触发的异常)
- 作用:专门捕获 HTTP 状态码不合法的问题
except requests.exceptions.RequestException as e:
logs.error(e)
pytest.fail('请求异常,请检查系统或数据是否正常')
- 异常类型 :
requests库通用异常基类(兜底捕获) - 作用:捕获所有未被前面分支处理的请求异常(超时、参数错误、重定向异常等)
as e:接收异常详情,打印具体错误信息
return result
- 最终返回接口响应对象
- 调用方可以通过返回值获取:
result.text(响应文本)、result.json()(响应 JSON)、result.status_code(状态码)