forked from DxvLwRYF/apiAutoTest
移除保存响应字段,新增提取参数栏,按照{参数名: jsonpath} 语法从当前响应提取值放到参数池,其他用例使用`${参数名}`,详细见更新日志
This commit is contained in:
parent
8c87e41705
commit
0415a029ed
|
@ -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(没技术大佬,本站上的个人项目问题都可以在这里咨询)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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)"))
|
||||
|
|
Loading…
Reference in New Issue