feat(funcs): 优化函数热加载
- 优化函数热加载模块funcs.py(由字典反射改为装饰器) - 修复bug
This commit is contained in:
@@ -56,7 +56,7 @@ class TestAPI:
|
||||
@classmethod
|
||||
def new_case(cls, case_info: CaseInfo):
|
||||
ddt_data = case_info.ddt()
|
||||
print(ddt_data)
|
||||
print(f"测试数据:{ddt_data}")
|
||||
|
||||
ddt_title = [data.title for data in ddt_data]
|
||||
logger.info(f"{ddt_title=}")
|
||||
@@ -80,12 +80,12 @@ class TestAPI:
|
||||
logger.info(f"3,正在提取变量...")
|
||||
# 2,保存变量(接口关联)
|
||||
for var_name, extract_info in new_case_info.extract.items():
|
||||
print(var_name, extract_info)
|
||||
# logger.info(f"保存变量:{var_name}{extract_info}")
|
||||
exchanger.extract(resp, var_name, *extract_info)
|
||||
# 3,断言
|
||||
logger.info(f"4,正在断言...")
|
||||
assert_case_info = exchanger.replace(case_info) # 为断言加载变量
|
||||
print(assert_case_info)
|
||||
# logger.info(f"替换变量后:{assert_case_info}")
|
||||
assert_case_info.assert_all() # 执行断言
|
||||
|
||||
logger.info(f"用例执行结束:{case_info.title}".center(80, "="))
|
||||
|
||||
@@ -85,7 +85,7 @@ if __name__ == '__main__':
|
||||
|
||||
# print(mock_resp.text)
|
||||
# print(mock_resp.json())
|
||||
exchanger = Exchange(r"D:\CNWei\CNW\InterfaceAutoTest\extract.yaml")
|
||||
exchanger = Exchange(r"E:\PyP\InterfaceAutoTest\extract.yaml")
|
||||
exchanger.extract(mock_resp, "name", "json", '$.name', 0)
|
||||
exchanger.extract(mock_resp, "age", "json", '$.age', 0)
|
||||
exchanger.extract(mock_resp, "data", "json", '$.data', 0)
|
||||
|
||||
@@ -22,25 +22,48 @@ from commons import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Funcs:
|
||||
|
||||
FUNC_MAPPING = {
|
||||
"int": int,
|
||||
"float": float,
|
||||
"bool": bool
|
||||
} # 内置函数有的,直接放入mapping;内置函数没有的,在funcs中定义,自动放入mapping
|
||||
|
||||
|
||||
@classmethod
|
||||
def register(cls, name: str):
|
||||
def decorator(func):
|
||||
cls.FUNC_MAPPING[name] = func
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
||||
@Funcs.register("url_unquote")
|
||||
def url_unquote(s: str) -> str:
|
||||
return urllib.parse.unquote(s)
|
||||
|
||||
|
||||
@Funcs.register("str")
|
||||
def to_string(s) -> str:
|
||||
# 将数据转换为str类型。
|
||||
return f"'{s}'"
|
||||
|
||||
@Funcs.register("time_str")
|
||||
def time_str() -> str:
|
||||
return str(time.time())
|
||||
|
||||
|
||||
@Funcs.register("add")
|
||||
def add(a, b):
|
||||
return str(int(a) + int(b))
|
||||
|
||||
|
||||
@Funcs.register("sql")
|
||||
def sql(s: str) -> str:
|
||||
res = db.execute_sql(s)
|
||||
|
||||
return res[0][0]
|
||||
|
||||
|
||||
@Funcs.register("new_id")
|
||||
def new_id():
|
||||
# 自增,永不重复
|
||||
id_file = YamlFile(settings.id_path)
|
||||
@@ -49,21 +72,21 @@ def new_id():
|
||||
|
||||
return id_file["id"]
|
||||
|
||||
|
||||
@Funcs.register("last_id")
|
||||
def last_id() -> str:
|
||||
# 不自增,只返回结果
|
||||
|
||||
id_file = YamlFile(settings.id_path)
|
||||
return id_file["id"]
|
||||
|
||||
|
||||
@Funcs.register("md5")
|
||||
def md5(content: str) -> str:
|
||||
# 1,原文转为字节
|
||||
content = content.encode("utf-8")
|
||||
result = hashlib.md5(content).hexdigest()
|
||||
return result
|
||||
|
||||
|
||||
@Funcs.register("base64_encode")
|
||||
def base64_encode(content: str) -> str:
|
||||
# 1,原文转二进制
|
||||
content = content.encode("utf-8")
|
||||
@@ -74,7 +97,7 @@ def base64_encode(content: str) -> str:
|
||||
|
||||
return encode_str
|
||||
|
||||
|
||||
@Funcs.register("base64_decode")
|
||||
def base64_decode(content: str) -> str:
|
||||
# 1,原文转二进制
|
||||
content = content.encode("utf-8")
|
||||
@@ -85,11 +108,11 @@ def base64_decode(content: str) -> str:
|
||||
|
||||
return decode_str
|
||||
|
||||
|
||||
@Funcs.register("rsa_encode")
|
||||
def rsa_encode(content: str) -> str:
|
||||
...
|
||||
|
||||
|
||||
@Funcs.register("rsa_decode")
|
||||
def rsa_decode(content: str) -> str:
|
||||
...
|
||||
|
||||
@@ -97,5 +120,6 @@ def rsa_decode(content: str) -> str:
|
||||
if __name__ == '__main__':
|
||||
# res = url_unquote("%E6%88%90%E5%8A%9F%E3%80%82")
|
||||
# print(res)
|
||||
print(f"计数器:{new_id()}")
|
||||
print(f"当前数值:{last_id()}")
|
||||
# print(f"计数器:{new_id()}")
|
||||
# print(f"当前数值:{last_id()}")
|
||||
print(Funcs().FUNC_MAPPING)
|
||||
@@ -51,9 +51,11 @@ class CaseInfo:
|
||||
def assert_all(self):
|
||||
_validator = case_validator.CaseValidator()
|
||||
# print(case_validator.VALIDATORS)
|
||||
|
||||
if not self.validate:
|
||||
return
|
||||
|
||||
_validator.assert_all(self.validate)
|
||||
# if not self.validate:
|
||||
# return
|
||||
# for assert_type, assert_value in self.validate.items():
|
||||
# for msg, data in assert_value.items():
|
||||
# a, b = data[0], data[1]
|
||||
@@ -77,12 +79,17 @@ class CaseInfo:
|
||||
case_list = []
|
||||
if not self.parametrize: # 没有使用数据驱动测试
|
||||
logger.info("1,执行这一步")
|
||||
case_list.append('')
|
||||
# case_info_str = self.to_yaml() # 转字符串
|
||||
# case_info_str = Template(case_info_str).render(d) # 输入变量
|
||||
# case_info = self.by_yaml(case_info_str) # 转成类
|
||||
# case_list.append(case_info)
|
||||
case_list.append(self)
|
||||
else: # 使用数据驱动测试
|
||||
args_name = self.parametrize[0]
|
||||
args_value_list = self.parametrize[1:]
|
||||
for args_value in args_value_list:
|
||||
d = dict(zip(args_name, args_value))
|
||||
print(f"D的值:{d}")
|
||||
# d 就是数据驱动测试的变量,应输入到用例中
|
||||
case_info_str = self.to_yaml() # 转字符串
|
||||
case_info_str = Template(case_info_str).render(d) # 输入变量
|
||||
@@ -93,11 +100,13 @@ class CaseInfo:
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
with open(r'E:\PyP\InterfaceAutoTest\TestCases\test_1_user.yaml', encoding='utf-8') as f:
|
||||
with open(r'E:\PyP\InterfaceAutoTest\TestCases\answer\test_1_status.yaml', encoding='utf-8') as f:
|
||||
data = yaml.safe_load(f)
|
||||
# print(data)
|
||||
case_info = CaseInfo(**data)
|
||||
s = case_info.to_yaml()
|
||||
print(s)
|
||||
# print(s)
|
||||
new_case_info = case_info.by_yaml(s)
|
||||
print(new_case_info)
|
||||
# print(new_case_info)
|
||||
ddt_ddt = case_info.ddt()
|
||||
print(ddt_ddt)
|
||||
|
||||
@@ -14,26 +14,23 @@ import logging
|
||||
import re
|
||||
import string
|
||||
import inspect
|
||||
from commons.funcs import Funcs
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _str(s) -> str:
|
||||
# 将数据转换为str类型。
|
||||
return f"'{s}'"
|
||||
|
||||
|
||||
class Template(string.Template):
|
||||
"""
|
||||
1,支持函数调用
|
||||
2,参数也可以是变量
|
||||
"""
|
||||
func_mapping = {
|
||||
"str": _str,
|
||||
"int": int,
|
||||
"float": float,
|
||||
"bool": bool
|
||||
} # 内置函数有的,直接放入mapping;内置函数没有的,在funcs中定义,自动放入mapping
|
||||
|
||||
# FUNC_MAPPING = {
|
||||
# "int": int,
|
||||
# "float": float,
|
||||
# "bool": bool
|
||||
# } # 内置函数有的,直接放入mapping;内置函数没有的,在funcs中定义,自动放入mapping
|
||||
|
||||
call_pattern = re.compile(r"\${(?P<func_name>.*?)\((?P<func_args>.*?)\)}")
|
||||
|
||||
@@ -51,8 +48,10 @@ class Template(string.Template):
|
||||
:return: 替换后的结果
|
||||
"""
|
||||
mapping = copy.deepcopy(mapping)
|
||||
mapping.update(self.func_mapping) # 合并两个mapping
|
||||
|
||||
logger.info(f"mapping更新前: {mapping}")
|
||||
# mapping.update(self.FUNC_MAPPING) # 合并两个mapping
|
||||
mapping.update(Funcs.FUNC_MAPPING) # 合并两个mapping
|
||||
logger.info(f"mapping更新后: {mapping}")
|
||||
def convert(mo):
|
||||
func_name = mo.group("func_name")
|
||||
func_args = mo.group("func_args").split(",")
|
||||
@@ -70,19 +69,27 @@ class Template(string.Template):
|
||||
return self.call_pattern.sub(convert, template)
|
||||
|
||||
|
||||
def hot_load():
|
||||
from commons import funcs
|
||||
for func_name in dir(funcs): # 遍历模块中的所有函数
|
||||
if func_name.startswith("_"):
|
||||
continue
|
||||
func_code = getattr(funcs, func_name) # 取到函数对象
|
||||
# print(func_code)
|
||||
if callable(func_code): # 如果是一个可以调用的函数
|
||||
Template.func_mapping[func_name] = func_code # 函数放到Template中
|
||||
print(Template.func_mapping)
|
||||
# if inspect.isfunction(func_code): # 如果是一个可以调用的函数
|
||||
# Template.func_mapping[func_name] = func_code # 函数放到Template中
|
||||
# print(Template.func_mapping)
|
||||
# def hot_load():
|
||||
# from commons import funcs
|
||||
#
|
||||
# for func_name in dir(funcs): # 遍历模块中的所有函数
|
||||
# if func_name.startswith("_"):
|
||||
# continue
|
||||
# func_code = getattr(funcs, func_name) # 取到函数对象
|
||||
# # print(func_code)
|
||||
# if callable(func_code): # 如果是一个可以调用的函数
|
||||
# Template.FUNC_MAPPING[func_name] = func_code # 函数放到Template中
|
||||
# print(Template.FUNC_MAPPING)
|
||||
# # if inspect.isfunction(func_code): # 如果是一个可以调用的函数
|
||||
# # Template.FUNC_MAPPING[func_name] = func_code # 函数放到Template中
|
||||
# # print(Template.FUNC_MAPPING)
|
||||
|
||||
|
||||
hot_load()
|
||||
# def hot_load():
|
||||
# from commons.funcs import Funcs
|
||||
#
|
||||
# print(Funcs.FUNC_MAPPING)
|
||||
# # if inspect.isfunction(func_code): # 如果是一个可以调用的函数
|
||||
# # Template.FUNC_MAPPING[func_name] = func_code # 函数放到Template中
|
||||
# # print(Template.FUNC_MAPPING)
|
||||
#
|
||||
# hot_load()
|
||||
|
||||
Reference in New Issue
Block a user