移除保存响应字段,新增提取参数栏,按照{参数名: jsonpath} 语法从当前响应提取值放到参数池,其他用例使用`${参数名}`,详细见更新日志

This commit is contained in:
zy7y 2021-05-19 12:31:25 +08:00
parent 8c87e41705
commit 0415a029ed
5 changed files with 47 additions and 57 deletions

View File

@ -122,6 +122,8 @@ https://www.bilibili.com/video/BV1EE411B7SU?p=10
2021/05/17 解决执行sql时datetime时间无法被序列化问题调试sql理论上支持所有sql语句(select,delete,update,select...), select语句只能获取结果集第一条数据
2021/05/19 统一使用`${}`来包裹变量名/方法 替代先前版本的`&&`,`@@`,新增提取参数栏,意为从当前接口响应中提取指定参数
2021/05/19 移除保存响应,增加提取参数栏{参数名: jsonpath} jsonpath为当前用例响应结果中提取并把结果给参数名其他用中`${参数名}`使用,`${方法名()}`,`${方法名(参数1)}`
## 博客园首发
https://www.cnblogs.com/zy7y/p/13426816.html
@ -130,7 +132,7 @@ https://www.cnblogs.com/zy7y/p/13426816.html
https://www.cnblogs.com/zy7y/p/13448102.html
## 视频教程该视频为2020年8月开源时录制大致内容是简单讲个文件作用其代码对应目前的version1.0分支)
B站https://www.bilibili.com/video/BV1pv411i7zK/
## 联系我
## 交流群
QQ群851163511没技术大佬本站上的个人项目问题都可以在这里咨询

View File

@ -33,9 +33,9 @@ class BaseRequest(object):
:param env: 环境名称 默认使用config.yaml server下的 dev 后面的基准地址
return: 响应结果 预期结果
"""
case_number, case_title, header, path, method, parametric_key, file_obj, data, sql, expect, is_save = case
case_number, case_title, header, path, method, parametric_key, file_obj, data, extra, sql, expect = case
logger.debug(
f"用例进行处理前数据: \n 接口路径: {path} \n 请求参数: {data} \n 后置sql: {sql} \n 预期结果: {expect} \n 保存响应: {is_save}")
f"用例进行处理前数据: \n 接口路径: {path} \n 请求参数: {data} \n 提取参数: {extra} \n 后置sql: {sql} \n 预期结果: {expect} \n ")
# allure报告 用例标题
allure_title(case_title)
# 处理url、header、data、file、的前置方法
@ -46,10 +46,8 @@ class BaseRequest(object):
file = DataProcess.handler_files(file_obj)
# 发送请求
response = cls.send_api(url, method, parametric_key, header, data, file)
# 保存用例的实际响应
if is_save == "":
DataProcess.save_response(case_number, response)
# 提取参数
DataProcess.handle_extra(extra, response)
return response, expect, sql
@classmethod

View File

@ -9,6 +9,7 @@
"""
import json
import re
from string import Template
import allure
@ -18,6 +19,17 @@ from loguru import logger
from tools.hooks import *
def exec_func(func: str) -> str:
"""执行函数(exec可以执行Python代码)
:params func 字符的形式调用函数
: return 返回的将是个str类型的结果
"""
# 得到一个局部的变量字典来修正exec函数中的变量在其他函数内部使用不到的问题
loc = locals()
exec(f"result = {func}")
return str(loc['result'])
def extractor(obj: dict, expr: str = '.') -> object:
"""
根据表达式提取字典中的value表达式, . 提取字典所有内容 $.case 提取一级字典case $.case.data 提取case字典下的data
@ -33,23 +45,18 @@ def extractor(obj: dict, expr: str = '.') -> object:
return result
def rep_expr(content: str, data: dict, expr: str = '&(.*?)&') -> str:
def rep_expr(content: str, data: dict) -> str:
"""从请求参数的字符串中,使用正则的方法找出合适的字符串内容并进行替换
:param content: 原始的字符串内容
:param data: 在该项目中一般为响应字典从字典取值出来
:param expr: 查找用的正则表达式
:param data: 提取的参数变量池
return content 替换表达式后的字符串
"""
for ctt in re.findall(expr, content):
content = content.replace(f'&{ctt}&', str(extractor(data, ctt)))
# 增加自定义函数得的调用函数写在tools/hooks.py中
for func in re.findall('@(.*?)@', content):
content = Template(content).safe_substitute(data)
for func in re.findall('\\${(.*?)}', content):
try:
content = content.replace(f'@{func}@', exec_func(func))
content = content.replace('${%s}' % func, exec_func(func))
except Exception as e:
logger.error(e)
continue
return content

View File

@ -13,31 +13,20 @@ from tools.read_file import ReadFile
class DataProcess:
response_dict = {}
# 存放提取参数的池子
extra_pool = {}
header = ReadFile.read_config('$.request_headers')
@classmethod
def save_response(cls, key: str, value: object) -> None:
"""
保存实际响应
:param key: 保存字典中的key一般使用用例编号
:param value: 保存字典中的value使用json响应
"""
cls.response_dict[key] = value
logger.info(f'添加key: {key}, 对应value: {value}')
allure_step('存储实际响应', cls.response_dict)
@classmethod
def handle_path(cls, path_str: str, env: str) -> str:
"""路径参数处理
:param path_str: 带提取表达式的字符串 /&$.case_005.data.id&/state/&$.case_005.data.create_time&
:param path_str: 带提取表达式的字符串 /${id}/state/${create_time}
:param env: 环境名称 对应的是环境基准地址
上述内容表示响应字典中提取到case_005字典里data字典里id的值假设是500后面&$.case_005.data.create_time& 类似最终提取结果
上述内容表示从extra_pool字典里取到key为id 对应的值假设是500后面${create_time} 类似 假设其值为 1605711095 最终提取结果
return /511/state/1605711095
"""
# /&$.case.data.id&/state/&$.case_005.data.create_time&
url = ReadFile.read_config(
f'$.server.{env}') + rep_expr(path_str, cls.response_dict)
f'$.server.{env}') + rep_expr(path_str, cls.extra_pool)
allure_step_no(f'请求地址: {url}')
return url
@ -79,7 +68,7 @@ class DataProcess:
return 处理之后的json/dict类型的字典数据
"""
if variable != '':
data = rep_expr(variable, cls.response_dict)
data = rep_expr(variable, cls.extra_pool)
variable = convert_json(data)
return variable
@ -93,7 +82,7 @@ class DataProcess:
:param db: 数据库连接对象
:return:
"""
sql = rep_expr(sql, DataProcess.response_dict)
sql = rep_expr(sql, cls.extra_pool)
for sql in sql.split(";"):
sql = sql.strip()
@ -106,7 +95,21 @@ class DataProcess:
if result is not None:
# 将查询结果添加到响应字典里面,作用在,接口响应的内容某个字段 直接和数据库某个字段比对,在预期结果中
# 使用同样的语法提取即可
DataProcess.response_dict.update(result)
DataProcess.extra_pool.update(result)
@classmethod
def handle_extra(cls, extra_str: str, response: dict):
"""
处理提取参数栏
:param extra_str: excel中 提取参数栏内容需要是 {"参数名": "jsonpath提取式"} 可以有多个
:param response: 当前用例的响应结果字典
"""
if extra_str != '':
extra_dict = convert_json(extra_str)
for k, v in extra_dict.items():
cls.extra_pool[k] = extractor(response, v)
logger.info(f'加入依赖字典,key: {k}, 对应value: {v}')
allure_step("当前可用参数池", cls.extra_pool)
@classmethod
def assert_result(cls, response: dict, expect_str: str):
@ -116,7 +119,7 @@ class DataProcess:
return None
"""
# 后置sql变量转换
expect_str = rep_expr(expect_str, DataProcess.response_dict)
expect_str = rep_expr(expect_str, cls.extra_pool)
expect_dict = convert_json(expect_str)
index = 0
for k, v in expect_dict.items():

View File

@ -16,17 +16,6 @@ import json
import time
def exec_func(func: str) -> str:
"""执行函数(exec可以执行Python代码)
:params func 字符的形式调用函数
: return 返回的将是个str类型的结果
"""
# 得到一个局部的变量字典来修正exec函数中的变量在其他函数内部使用不到的问题
loc = locals()
exec(f"result = {func}")
return str(loc['result'])
def get_current_highest():
"""获取当前时间戳"""
return int(time.time())
@ -41,12 +30,3 @@ def set_token(token: str):
"""设置token直接返回字典"""
return {"Authorization": token}
if __name__ == '__main__':
# 实例, 调用无参数方法 get_current_highest
result = exec_func("get_current_highest()")
print(result)
# 调用有参数方法 sum_data
print(exec_func("sum_data(1,3)"))