在接口自动化测试中,对 HTTP 响应的处理是一个非常关键的环节。我们不仅需要从响应中提取关键字段(如 token、userId 等),还需要对接口返回结果进行断言验证,以确保接口功能符合预期。
本文将详细介绍一个基于 requests 和 jsonpath 的通用响应处理模块 result.py,它实现了两个核心功能:
该模块适用于自动化测试框架开发、接口联调、以及 API 测试等场景。
import typing as t
import pytest
import allure
from requests import Response
from common.cache import cache
from common.regular import get_var
from utils.logger import logger
import json
import logging
模块 | 用途 |
typing | 类型注解,增强代码可读性 |
pytest | 断言和测试支持 |
allure | 生成测试报告 |
Response | 来自 requests,用于处理 HTTP 响应 |
cache | 自定义缓存模块,用于存储提取的变量 |
get_var | 使用 JSONPath 提取响应中的值 |
logger | 日志记录工具 |
json / logging | JSON 解析和日志输出 |
def get_result(r: Response, extract: t.Dict) -> None:
"""
从响应中提取指定的值并存入缓存。
:param r: HTTP 响应对象
:param extract: 包含键和 JSONPath 表达式的字典
"""
response_json = r.json()
logger.debug("响应 JSON: {}".format(response_json))
for key, jsonpath_expr in extract.items():
value = get_var(jsonpath_expr, response_json)
if value is not None:
cache.set(key, value)
logger.info(f"成功存入缓存: {key}={value}")
else:
logger.error(f"无法提取 {key} 的值,路径: {jsonpath_expr}")
raise ValueError(f"提取失败: {key} 的路径 {jsonpath_expr} 无效")
logger.debug(f"当前缓存内容: {cache.data}") # 打印完整缓存内容
with allure.step("提取返回结果中的值"):
for key in extract.keys():
allure.attach(name=f"提取 {key}", body=str(cache.get(key)))
参数说明:
示例输入:
extract = {"token": "$.data.accessToken"}
作用:
response = Response()
response._content = json.dumps({"data": {"accessToken": "12345"}}).encode('utf-8')
extract = {"token": "$.data.accessToken"}
get_result(response, extract)
执行后,token 被缓存为 "12345",可通过 cache.get("token") 获取。
response_json = r.json()
for key, jsonpath_expr in extract.items():
value = get_var(jsonpath_expr, response_json)
if value is not None:
cache.set(key, value)
else:
raise ValueError(...)
with allure.step("提取返回结果中的值"):
allure.attach(name=f"提取 {key}", body=str(cache.get(key)))
def check_results(response: Response, validation: t.Dict) -> None:
"""
验证响应结果是否符合预期。
:param response: HTTP 响应对象
:param validation: 验证规则字典,包含 'type', 'actual', 'expected' 键
"""
try:
# 将响应文本转换为 JSON 对象
response_json = json.loads(response.text)
# 使用 get_nested_value 函数根据路径提取实际值
actual = get_nested_value(response_json, validation['actual'])
expected = validation['expected']
# 记录调试日志
# logger.debug(f"响应内容: {response.text}")
logger.debug(f"验证规则: {validation}")
logger.debug(f"实际值: {actual}, 预期值: {validation['expected']}")
# 根据验证规则类型进行处理
if validation['type'] == 'eq':
# 比较实际值和预期值是否相等
if actual != expected:
raise AssertionError(f"验证失败(eq比较实际值和预期值是否相等): 实际值 {actual} 不等于预期值 {expected}")
elif validation['type'] == 'not_eq':
# 比较实际值和预期值是否不相等
if actual == expected:
raise AssertionError(f"验证失败(not_eq比较实际值和预期值是否不相等): 实际值 {actual} 等于预期值 {expected}")
else:
# 如果验证规则类型未知,记录错误日志并抛出异常
logger.error(f"未知的验证规则类型: {validation['type']}")
raise ValueError(f"无效的验证规则: {validation['type']}")
except Exception as e:
# 记录错误日志并重新抛出异常
logger.error(f"处理验证规则时发生错误: {e}\n原始响应内容: {response.text}")
raise e
参数说明:
示例输入:
validation = {"type": "eq", "actual": "$.data.accessToken", "expected": "12345"}
作用:
validation = {"type": "eq", "actual": "$.data.accessToken", "expected": "12345"}
check_results(response, validation)
如果实际值是 "12345",则验证通过;否则抛出 AssertionError。
response_json = json.loads(response.text)
actual = get_nested_value(response_json, validation['actual'])
if validation['type'] == 'eq':
assert actual == expected
elif validation['type'] == 'not_eq':
assert actual != expected
except Exception as e:
logger.error(f"处理验证规则时发生错误: {e}")
raise e
def get_nested_value(d, path):
"""
根据路径从字典中提取嵌套的值。
:param d: 字典对象
:param path: 路径字符串,例如 "data.accessToken"
:return: 提取的值,如果路径不存在则返回 None
"""
if not path.startswith('$'):
# 如果路径不是 JSONPath 格式,直接返回 None
return None
try:
# 使用 jsonpath 提取值
import jsonpath
result = jsonpath.jsonpath(d, path)
if result and len(result) > 0:
return result[0]
return None
except Exception as e:
logger.error(f"JSONPath 解析错误: {e}")
return None
该函数用于从嵌套结构中提取字段值,支持标准 JSONPath 表达式。
d = {"data": {"accessToken": "abc"}}
path = "$.data.accessToken"
"abc"
方法 | 功能 |
get_result | 从响应中提取字段并缓存,供后续使用 |
check_results | 验证响应内容是否符合预期 |
get_nested_value | 支持 JSONPath 提取字段值 |
# 登录接口提取 token
get_result(login_response, {"token": "$.data.accessToken"})
# 使用 token 发起其他请求
headers = {"Authorization": f"Bearer {cache.get('token')}"}
validation = {"type": "eq", "actual": "$.code", "expected": 0}
check_results(response, validation)
"abc"
这篇文章我们介绍了一个实用的小模块,专门用来处理接口返回的数据。它可以:
这个模块结构清晰、功能实用,特别适合用在自动化测试中,帮助我们更好地管理和验证接口数据。