调整响应数据提取,支持通过yaml用例数据传参提取指定格式的参数

支持3种类型的数据提取:1. 通过jsonpath从response.json()提取数据; 2. 通过正则表达式从response.text提取; 3. 直接从response提取cookies之类;
This commit is contained in:
floraachy
2023-12-05 14:02:27 +08:00
parent 3b3c8e6a62
commit a01db401bf
9 changed files with 131 additions and 79 deletions

View File

@@ -305,11 +305,9 @@ class DataHandle:
"""
func = {}
keys = {}
if not source or not isinstance(source, dict):
# logger.debug("source为空或者source不是字典格式都将认为是{}")
source = {}
else:
logger.debug(f"source={source}")
source = {} if not source or not isinstance(source, dict) else source
logger.trace(f"source={source}")
# 处理一下source检测到里面存在RequestsCookieJar转成dict再转换成JSON 格式的字符串(序列化)。
# 避免传递过来一个RequestsCookieJar替换后变成了'RequestsCookieJar'导致cookies无法使用的问题
@@ -429,7 +427,7 @@ if __name__ == '__main__':
"nested_data": [
"This is ${name}'s data.",
{
"message": "Age: ${generate_random_int()",
"message": "Age: ${generate_random_int()}",
"nested_list": [
"More data: ${FakerData().generate_random_int()}",
]
@@ -520,4 +518,3 @@ if __name__ == '__main__':
new = data_handle(data)
print(new, type(new),
end="\n\n---------------------------------------------------------------------------------------------\n\n")

View File

@@ -10,52 +10,62 @@ import re
# 第三方库导入
from jsonpath import jsonpath
from loguru import logger
from requests import Response
def json_extractor(obj: dict, expr: str = '.'):
"""
从目标对象obj, 根据表达式expr提取指定的值
:param obj :json/dict类型数据
:param expr: 表达式, . 提取字典所有内容, $.test_api_case 提取一级字典case $.test_api_case.data 提取case字典下的data
:return result: 提取的结果,未提取到返回 None
"""
try:
# 如果提取后的数据长度为1则取第一个元素返回str否则返回列表
result = jsonpath(obj, expr)[0] if len(jsonpath(obj, expr)) == 1 else jsonpath(obj, expr)
logger.trace("\n======================================================\n" \
"-------------Startjson_extractor--------------------\n"
f"提取表达式为: {expr} \n"
f"提取值为: {result}\n"
"=====================================================")
logger.trace(f"\n提取表达式: {expr} \n"
f"提取值类型: {type(result)}\n"
f"提取值:{result}\n")
return result
except Exception as e:
logger.trace("\n======================================================\n" \
"-------------Endjson_extractor--------------------\n"
f"提取表达式为: {expr}\n"
f"提取数据为: {obj}\n"
f"错误信息为:{e}\n"
"=====================================================")
result = None
return result
logger.trace(f"\n提取表达式: {expr}\n"
f"提取对象: {obj}\n"
f"错误信息:{e}\n")
def re_extract(obj: str, expr: str = '.'):
"""
从目标对象obj, 根据表达式expr提取指定的值
:param obj : 字符串数据
:param expr: 正则表达式
:return result: 提取的结果,未提取到返回 None
"""
try:
result = re.findall(expr, obj)[0]
logger.trace("\n======================================================\n" \
"-------------Startre_extract--------------------\n"
f"提取表达式为 {expr}\n" \
f"提取值为: {result}\n" \
"=====================================================")
# 如果提取后的数据长度为1则取第一个元素返回str否则返回列表
result = re.findall(expr, obj)[0] if len(re.findall(expr, obj)) == 1 else re.findall(expr, obj)
logger.debug(f"\n提取表达式: {expr}\n"
f"提取值类型 {type(result)}\n"
f"提取值{result}\n")
return result
except Exception as e:
logger.trace(f"\n======================================================\n" \
"-------------Endre_extract--------------------\n"
f"提取表达式为: {expr}\n" \
f"提取数据为: {obj}\n" \
f"错误信息为:{e}\n" \
"=====================================================")
result = None
return result
logger.debug(f"\n提取表达式: {expr}\n"
f"提取对象: {obj}\n"
f"错误信息:{e}\n")
def response_extract(response: Response, expr: str = '.'):
"""
response响应对象提取cookies之类
:param response : response对象
:param expr: 提取表达式。部分参考response.status_code response.cookies, response.text, response.headers, response.is_redirect
:return result: 提取的结果,未提取到返回 None
"""
try:
result = eval(expr)
logger.debug(f"\n提取表达式: {expr}\n"
f"提取值类型: {type(result)}\n"
f"提取值:{result}\n")
return result
except Exception as e:
logger.debug(f"\n提取表达式: {expr}\n"
f"提取对象: {response}\n"
f"错误信息:{e}\n")

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# @Time : 2023/12/5 10:19
# @Author : floraachy
# @File : handle_eval_data
# @Software: PyCharm
# @Desc:
# 第三方库导入
from loguru import logger
# 将"[1,2,3]" 或者"{'k':'v'}" -> [1,2,3], {'k':'v'}
def eval_data(data):
"""
执行一个字符串表达式,并返回其表达式的值
"""
try:
if hasattr(eval(data), "__call__"):
return data
else:
return eval(data)
except Exception as e:
logger.trace(f"{data} --> 该数据不能被eval\n报错:{e}")
return data

View File

@@ -14,13 +14,13 @@ import http.cookiejar
from requests import Response
from loguru import logger
# 本地应用/模块导入
from common_utils.other_utils.files_handle import get_file_field
from case_utils.requests_utils.base_request import BaseRequest
from case_utils.requests_utils.data_handle import data_handle
from case_utils.requests_utils.extract_data_handle import json_extractor, re_extract
from case_utils.requests_utils.extract_data_handle import json_extractor, re_extract, response_extract
from case_utils.report_utils.allure_handle import allure_step
from config.global_vars import GLOBAL_VARS
from config.path_config import FILES_DIR
from case_utils.requests_utils.handle_eval_data import eval_data
# ---------------------------------------- 请求前的数据处理----------------------------------------#
@@ -210,35 +210,47 @@ class RequestHandle:
# ---------------------------------------- 请求后的参数提取处理----------------------------------------#
def after_request_extract(response: Response, extract):
"""
从响应数据中提取请求后的参数,并保存到全局变量中
:param response: request 响应对象
:param extract: 需要提取的参数字典 '{"k1": "$.data"}''{"k1": "data:(.*?)$"}'
:return:
"""
logger.debug(f"\n======================================================\n" \
"-------------Start:从响应数据中提取后置参数保存到全局变量--------------------\n"
f"后置提取参数(原): {extract}\n" \
"=====================================================")
result = {}
从响应数据中提取请求后的参数,并保存到全局变量中
:param response: request 响应对象
:param extract: 需要提取的参数字典 '{"k1": "$.data"}''{"k1": "data:(.*?)$"}'
:return:
"""
logger.debug(f"\n================================================================================\n" \
"-------------Start: 提取表达式--------------------\n"
f"后置提取参数(原): {extract}\n")
json_result = {}
re_result = {}
response_result = {}
if extract:
if response_type(response) == "json":
if extract.get("type_json"):
# 如果响应数据是json格式则将按照json方式对后置提取参数进行处理
res = response.json()
for k, v in extract.items():
result[k] = json_extractor(res, v)
else:
for k, v in extract["type_json"].items():
json_result[k] = json_extractor(res, v)
logger.debug("-------------从response.json()中通过jsonpath方式提取到的结果--------------------\n"
f"后置提取参数(新): {json_result}\n")
if extract.get("type_re"):
# 如果响应数据是str格式则将按照str方式对后置提取参数进行处理
res = response.text
for k, v in extract.items():
result[k] = re_extract(res, v)
logger.debug(f"\n======================================================\n" \
"-------------End从响应数据中提取后置参数保存到全局变量--------------------\n"
f"后置提取参数(新): {result}\n" \
"=====================================================")
for k, v in extract["type_re"].items():
re_result[k] = re_extract(res, v)
logger.debug("-------------从response.text中通过正则表达式提取到的结果--------------------\n"
f"后置提取参数(新): {re_result}\n")
if extract.get("type_response"):
for k, v in extract["type_response"].items():
response_result[k] = response_extract(response, v)
logger.debug("-------------从response中提取到的结果--------------------\n"
f"后置提取参数(新): {re_result}\n")
result = {**json_result, **re_result, **response_result}
# 将提取到的变量保存在全局变量中
if result:
for k, v in result.items():
GLOBAL_VARS[k] = v
GLOBAL_VARS[k] = eval_data(v)
result[k] = eval_data(v)
logger.info("-------------End所有提取到的结果--------------------\n"
f"后置提取参数(新): {result}\n" \
"================================================================================")
return result

View File

@@ -90,7 +90,7 @@ class RunConfig:
CASE_FILE_TYPE = 1
# 0表示默认不发送任何通知 1代表钉钉通知2代表企业微信通知 3代表邮件通知 4代表所有途径都发送通知
SEND_RESULT_TYPE = 1
SEND_RESULT_TYPE = 0
# 指定日志收集级别
LOG_LEVEL = "DEBUG"

View File

@@ -13,12 +13,15 @@ case_info:
title: 获取已报名成功的项目数据
severity: normal
run: True
url: ${glcc_host}/api/applyInformation/list?curPage=1&pageSize=10000&round=2
url: ${glcc_host}/api/applyInformation/list
method: GET
headers: {"Content-Type": "application/json; charset=utf-8;"}
cookies:
request_type: json
request_type: params
payload:
curPage: 1
pageSize: 10000
round: 2
files:
extract:
assert_response:
@@ -32,12 +35,15 @@ case_info:
title: 获取已报名成功的课题数据
severity: normal
run: True
url: https://glcc.gitlink.org.cn/api/applyInformation/taskList?curPage=1&pageSize=20&userId=&round=2
url: ${glcc_host}/api/applyInformation/taskList
method: GET
headers: {"Content-Type": "application/json; charset=utf-8;"}
cookies:
request_type: json
request_type: params
payload:
curPage: 1
pageSize: 20
round: 2
files:
extract:
assert_response:

View File

@@ -22,9 +22,10 @@ case_info:
payload: { "login": "${login}","password": "${password}","autologin": 1 }
files:
extract:
nickname: $.username
login: $.login
user_id: $.user_id
type_re:
nickname: \"username":"(.*?)"
login: \"login":"(.*?)"
user_id: \"user_id":(.*?),
assert_response:
eq:
http_code: 200

View File

@@ -23,14 +23,15 @@ case_info:
cookies:
request_type: json
payload:
"user_id": ${user_id}
"name": ${generate_name(lan='zh')}_${generate_identifier()}
"repository_name": ${generate_identifier()}
user_id: ${user_id}
name: ${generate_name(lan='zh')}_${generate_identifier()}
repository_name: ${generate_identifier()}
files:
extract:
project_id: $.id
project_name: $.name
project_identifier: $.identifier
type_json:
project_id: $.id
project_name: $.name
project_identifier: $.identifier
assert_response:
eq:
http_code: 200
@@ -48,9 +49,9 @@ case_info:
cookies: ${login_cookie}
request_type: json
payload:
"user_id": ${user_id}
"name": ${generate_name(lan='zh')}_${generate_identifier()}
"repository_name": ${generate_identifier()}
user_id: ${user_id}
name: ${generate_name(lan='zh')}_${generate_identifier()}
repository_name: ${generate_identifier()}
files:
extract:
project_id: $.id
@@ -73,9 +74,9 @@ case_info:
cookies:
request_type: json
payload:
"user_id": ${user_id}
"name": ${generate_name(lan='zh')}_${generate_identifier()}
"repository_name": ${generate_identifier()}
user_id: ${user_id}
name: ${generate_name(lan='zh')}_${generate_identifier()}
repository_name: ${generate_identifier()}
files:
extract:
project_id: $.id

View File

@@ -24,7 +24,8 @@ case_info:
payload:
files: TOC出库订单导入模板(2).xlsx
extract:
file_id: $.id
type_json:
file_id: $.id
assert_response:
eq:
http_code: 200