feat(funcs): 优化函数热加载
- 优化函数热加载模块funcs.py(由字典反射改为装饰器) - 修复bug
This commit is contained in:
@@ -12,25 +12,20 @@ request:
|
|||||||
Referer: http://119.91.19.171:40065/users/login
|
Referer: http://119.91.19.171:40065/users/login
|
||||||
Accept-Encoding: gzip, deflate
|
Accept-Encoding: gzip, deflate
|
||||||
extract: # 提取变量
|
extract: # 提取变量
|
||||||
code:
|
|
||||||
- "json"
|
|
||||||
- "$.code"
|
|
||||||
- 0
|
|
||||||
msg:
|
msg:
|
||||||
- "json"
|
- "json"
|
||||||
- "$.msg"
|
- "$.msg"
|
||||||
- 0
|
- 0
|
||||||
|
|
||||||
|
|
||||||
validate:
|
validate:
|
||||||
equals: # 断言相等
|
equals: # 断言相等
|
||||||
状态码等于200:
|
状态码等于200:
|
||||||
- Success.
|
- Success.
|
||||||
- ${msg}
|
- ${msg}
|
||||||
|
|
||||||
parametrize: # 数据驱动测试
|
#parametrize: # 数据驱动测试
|
||||||
- [ "title","username","password","code" ] # 变量名
|
# - [ "title","username","password","msg" ] # 变量名
|
||||||
- [ "测试1","user1","pass1","code1" ] # 变量值
|
# - [ "测试1","user1","pass1","200" ] # 变量值
|
||||||
- [ "测试2","user2","pass2","code2" ] # 变量值
|
# - [ "测试2","user2","pass2","300" ] # 变量值
|
||||||
- [ "测试3","user3","pass3","code3" ] # 变量值
|
# - [ "测试3","user3","pass3","200" ] # 变量值
|
||||||
- [ "测试4","user4","pass4","code4" ] # 变量值
|
# - [ "测试4","user4","pass4","200" ] # 变量值
|
||||||
@@ -56,7 +56,7 @@ class TestAPI:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def new_case(cls, case_info: CaseInfo):
|
def new_case(cls, case_info: CaseInfo):
|
||||||
ddt_data = case_info.ddt()
|
ddt_data = case_info.ddt()
|
||||||
print(ddt_data)
|
print(f"测试数据:{ddt_data}")
|
||||||
|
|
||||||
ddt_title = [data.title for data in ddt_data]
|
ddt_title = [data.title for data in ddt_data]
|
||||||
logger.info(f"{ddt_title=}")
|
logger.info(f"{ddt_title=}")
|
||||||
@@ -80,12 +80,12 @@ class TestAPI:
|
|||||||
logger.info(f"3,正在提取变量...")
|
logger.info(f"3,正在提取变量...")
|
||||||
# 2,保存变量(接口关联)
|
# 2,保存变量(接口关联)
|
||||||
for var_name, extract_info in new_case_info.extract.items():
|
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)
|
exchanger.extract(resp, var_name, *extract_info)
|
||||||
# 3,断言
|
# 3,断言
|
||||||
logger.info(f"4,正在断言...")
|
logger.info(f"4,正在断言...")
|
||||||
assert_case_info = exchanger.replace(case_info) # 为断言加载变量
|
assert_case_info = exchanger.replace(case_info) # 为断言加载变量
|
||||||
print(assert_case_info)
|
# logger.info(f"替换变量后:{assert_case_info}")
|
||||||
assert_case_info.assert_all() # 执行断言
|
assert_case_info.assert_all() # 执行断言
|
||||||
|
|
||||||
logger.info(f"用例执行结束:{case_info.title}".center(80, "="))
|
logger.info(f"用例执行结束:{case_info.title}".center(80, "="))
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
# print(mock_resp.text)
|
# print(mock_resp.text)
|
||||||
# print(mock_resp.json())
|
# 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, "name", "json", '$.name', 0)
|
||||||
exchanger.extract(mock_resp, "age", "json", '$.age', 0)
|
exchanger.extract(mock_resp, "age", "json", '$.age', 0)
|
||||||
exchanger.extract(mock_resp, "data", "json", '$.data', 0)
|
exchanger.extract(mock_resp, "data", "json", '$.data', 0)
|
||||||
|
|||||||
@@ -22,25 +22,48 @@ from commons import settings
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
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:
|
def url_unquote(s: str) -> str:
|
||||||
return urllib.parse.unquote(s)
|
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:
|
def time_str() -> str:
|
||||||
return str(time.time())
|
return str(time.time())
|
||||||
|
|
||||||
|
@Funcs.register("add")
|
||||||
def add(a, b):
|
def add(a, b):
|
||||||
return str(int(a) + int(b))
|
return str(int(a) + int(b))
|
||||||
|
|
||||||
|
@Funcs.register("sql")
|
||||||
def sql(s: str) -> str:
|
def sql(s: str) -> str:
|
||||||
res = db.execute_sql(s)
|
res = db.execute_sql(s)
|
||||||
|
|
||||||
return res[0][0]
|
return res[0][0]
|
||||||
|
|
||||||
|
@Funcs.register("new_id")
|
||||||
def new_id():
|
def new_id():
|
||||||
# 自增,永不重复
|
# 自增,永不重复
|
||||||
id_file = YamlFile(settings.id_path)
|
id_file = YamlFile(settings.id_path)
|
||||||
@@ -49,21 +72,21 @@ def new_id():
|
|||||||
|
|
||||||
return id_file["id"]
|
return id_file["id"]
|
||||||
|
|
||||||
|
@Funcs.register("last_id")
|
||||||
def last_id() -> str:
|
def last_id() -> str:
|
||||||
# 不自增,只返回结果
|
# 不自增,只返回结果
|
||||||
|
|
||||||
id_file = YamlFile(settings.id_path)
|
id_file = YamlFile(settings.id_path)
|
||||||
return id_file["id"]
|
return id_file["id"]
|
||||||
|
|
||||||
|
@Funcs.register("md5")
|
||||||
def md5(content: str) -> str:
|
def md5(content: str) -> str:
|
||||||
# 1,原文转为字节
|
# 1,原文转为字节
|
||||||
content = content.encode("utf-8")
|
content = content.encode("utf-8")
|
||||||
result = hashlib.md5(content).hexdigest()
|
result = hashlib.md5(content).hexdigest()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@Funcs.register("base64_encode")
|
||||||
def base64_encode(content: str) -> str:
|
def base64_encode(content: str) -> str:
|
||||||
# 1,原文转二进制
|
# 1,原文转二进制
|
||||||
content = content.encode("utf-8")
|
content = content.encode("utf-8")
|
||||||
@@ -74,7 +97,7 @@ def base64_encode(content: str) -> str:
|
|||||||
|
|
||||||
return encode_str
|
return encode_str
|
||||||
|
|
||||||
|
@Funcs.register("base64_decode")
|
||||||
def base64_decode(content: str) -> str:
|
def base64_decode(content: str) -> str:
|
||||||
# 1,原文转二进制
|
# 1,原文转二进制
|
||||||
content = content.encode("utf-8")
|
content = content.encode("utf-8")
|
||||||
@@ -85,11 +108,11 @@ def base64_decode(content: str) -> str:
|
|||||||
|
|
||||||
return decode_str
|
return decode_str
|
||||||
|
|
||||||
|
@Funcs.register("rsa_encode")
|
||||||
def rsa_encode(content: str) -> str:
|
def rsa_encode(content: str) -> str:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@Funcs.register("rsa_decode")
|
||||||
def rsa_decode(content: str) -> str:
|
def rsa_decode(content: str) -> str:
|
||||||
...
|
...
|
||||||
|
|
||||||
@@ -97,5 +120,6 @@ def rsa_decode(content: str) -> str:
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# res = url_unquote("%E6%88%90%E5%8A%9F%E3%80%82")
|
# res = url_unquote("%E6%88%90%E5%8A%9F%E3%80%82")
|
||||||
# print(res)
|
# print(res)
|
||||||
print(f"计数器:{new_id()}")
|
# print(f"计数器:{new_id()}")
|
||||||
print(f"当前数值:{last_id()}")
|
# print(f"当前数值:{last_id()}")
|
||||||
|
print(Funcs().FUNC_MAPPING)
|
||||||
@@ -51,9 +51,11 @@ class CaseInfo:
|
|||||||
def assert_all(self):
|
def assert_all(self):
|
||||||
_validator = case_validator.CaseValidator()
|
_validator = case_validator.CaseValidator()
|
||||||
# print(case_validator.VALIDATORS)
|
# print(case_validator.VALIDATORS)
|
||||||
|
|
||||||
|
if not self.validate:
|
||||||
|
return
|
||||||
|
|
||||||
_validator.assert_all(self.validate)
|
_validator.assert_all(self.validate)
|
||||||
# if not self.validate:
|
|
||||||
# return
|
|
||||||
# for assert_type, assert_value in self.validate.items():
|
# for assert_type, assert_value in self.validate.items():
|
||||||
# for msg, data in assert_value.items():
|
# for msg, data in assert_value.items():
|
||||||
# a, b = data[0], data[1]
|
# a, b = data[0], data[1]
|
||||||
@@ -77,12 +79,17 @@ class CaseInfo:
|
|||||||
case_list = []
|
case_list = []
|
||||||
if not self.parametrize: # 没有使用数据驱动测试
|
if not self.parametrize: # 没有使用数据驱动测试
|
||||||
logger.info("1,执行这一步")
|
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: # 使用数据驱动测试
|
else: # 使用数据驱动测试
|
||||||
args_name = self.parametrize[0]
|
args_name = self.parametrize[0]
|
||||||
args_value_list = self.parametrize[1:]
|
args_value_list = self.parametrize[1:]
|
||||||
for args_value in args_value_list:
|
for args_value in args_value_list:
|
||||||
d = dict(zip(args_name, args_value))
|
d = dict(zip(args_name, args_value))
|
||||||
|
print(f"D的值:{d}")
|
||||||
# d 就是数据驱动测试的变量,应输入到用例中
|
# d 就是数据驱动测试的变量,应输入到用例中
|
||||||
case_info_str = self.to_yaml() # 转字符串
|
case_info_str = self.to_yaml() # 转字符串
|
||||||
case_info_str = Template(case_info_str).render(d) # 输入变量
|
case_info_str = Template(case_info_str).render(d) # 输入变量
|
||||||
@@ -93,11 +100,13 @@ class CaseInfo:
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
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)
|
data = yaml.safe_load(f)
|
||||||
# print(data)
|
# print(data)
|
||||||
case_info = CaseInfo(**data)
|
case_info = CaseInfo(**data)
|
||||||
s = case_info.to_yaml()
|
s = case_info.to_yaml()
|
||||||
print(s)
|
# print(s)
|
||||||
new_case_info = case_info.by_yaml(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 re
|
||||||
import string
|
import string
|
||||||
import inspect
|
import inspect
|
||||||
|
from commons.funcs import Funcs
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _str(s) -> str:
|
|
||||||
# 将数据转换为str类型。
|
|
||||||
return f"'{s}'"
|
|
||||||
|
|
||||||
|
|
||||||
class Template(string.Template):
|
class Template(string.Template):
|
||||||
"""
|
"""
|
||||||
1,支持函数调用
|
1,支持函数调用
|
||||||
2,参数也可以是变量
|
2,参数也可以是变量
|
||||||
"""
|
"""
|
||||||
func_mapping = {
|
|
||||||
"str": _str,
|
# FUNC_MAPPING = {
|
||||||
"int": int,
|
# "int": int,
|
||||||
"float": float,
|
# "float": float,
|
||||||
"bool": bool
|
# "bool": bool
|
||||||
} # 内置函数有的,直接放入mapping;内置函数没有的,在funcs中定义,自动放入mapping
|
# } # 内置函数有的,直接放入mapping;内置函数没有的,在funcs中定义,自动放入mapping
|
||||||
|
|
||||||
call_pattern = re.compile(r"\${(?P<func_name>.*?)\((?P<func_args>.*?)\)}")
|
call_pattern = re.compile(r"\${(?P<func_name>.*?)\((?P<func_args>.*?)\)}")
|
||||||
|
|
||||||
@@ -51,8 +48,10 @@ class Template(string.Template):
|
|||||||
:return: 替换后的结果
|
:return: 替换后的结果
|
||||||
"""
|
"""
|
||||||
mapping = copy.deepcopy(mapping)
|
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):
|
def convert(mo):
|
||||||
func_name = mo.group("func_name")
|
func_name = mo.group("func_name")
|
||||||
func_args = mo.group("func_args").split(",")
|
func_args = mo.group("func_args").split(",")
|
||||||
@@ -70,19 +69,27 @@ class Template(string.Template):
|
|||||||
return self.call_pattern.sub(convert, template)
|
return self.call_pattern.sub(convert, template)
|
||||||
|
|
||||||
|
|
||||||
def hot_load():
|
# def hot_load():
|
||||||
from commons import funcs
|
# from commons import funcs
|
||||||
for func_name in dir(funcs): # 遍历模块中的所有函数
|
#
|
||||||
if func_name.startswith("_"):
|
# for func_name in dir(funcs): # 遍历模块中的所有函数
|
||||||
continue
|
# if func_name.startswith("_"):
|
||||||
func_code = getattr(funcs, func_name) # 取到函数对象
|
# continue
|
||||||
# print(func_code)
|
# func_code = getattr(funcs, func_name) # 取到函数对象
|
||||||
if callable(func_code): # 如果是一个可以调用的函数
|
# # print(func_code)
|
||||||
Template.func_mapping[func_name] = func_code # 函数放到Template中
|
# if callable(func_code): # 如果是一个可以调用的函数
|
||||||
print(Template.func_mapping)
|
# Template.FUNC_MAPPING[func_name] = func_code # 函数放到Template中
|
||||||
# if inspect.isfunction(func_code): # 如果是一个可以调用的函数
|
# print(Template.FUNC_MAPPING)
|
||||||
# Template.func_mapping[func_name] = func_code # 函数放到Template中
|
# # if inspect.isfunction(func_code): # 如果是一个可以调用的函数
|
||||||
# print(Template.func_mapping)
|
# # Template.FUNC_MAPPING[func_name] = func_code # 函数放到Template中
|
||||||
|
# # print(Template.FUNC_MAPPING)
|
||||||
|
|
||||||
|
# def hot_load():
|
||||||
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()
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
code: 200
|
|
||||||
msg: Success.
|
msg: Success.
|
||||||
|
id: 12
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
02/28/2025 02:08:06 PM [commons.cases] INFO cases.find_yaml_case:45 - 加载文件:D:\CNWei\CNW\InterfaceAutoTest\TestCases\answer\test_1_status.yaml
|
03/02/2025 09:38:14 PM [commons.cases] INFO cases.find_yaml_case:45 - 加载文件:E:\PyP\InterfaceAutoTest\TestCases\answer\test_1_status.yaml
|
||||||
02/28/2025 02:08:06 PM [commons.cases] INFO cases.find_yaml_case:50 - case_info=title: 查询状态信息
|
03/02/2025 09:38:14 PM [commons.cases] INFO cases.find_yaml_case:50 - case_info=title: 查询状态信息
|
||||||
request:
|
request:
|
||||||
method: get
|
method: get
|
||||||
url: /answer/api/v1/connector/info
|
url: /answer/api/v1/connector/info
|
||||||
@@ -12,10 +12,6 @@ request:
|
|||||||
Referer: http://119.91.19.171:40065/users/login
|
Referer: http://119.91.19.171:40065/users/login
|
||||||
Accept-Encoding: gzip, deflate
|
Accept-Encoding: gzip, deflate
|
||||||
extract:
|
extract:
|
||||||
code:
|
|
||||||
- json
|
|
||||||
- $.code
|
|
||||||
- 0
|
|
||||||
msg:
|
msg:
|
||||||
- json
|
- json
|
||||||
- $.msg
|
- $.msg
|
||||||
@@ -25,45 +21,34 @@ validate:
|
|||||||
状态码等于200:
|
状态码等于200:
|
||||||
- Success.
|
- Success.
|
||||||
- ${msg}
|
- ${msg}
|
||||||
parametrize:
|
parametrize: []
|
||||||
- - title
|
|
||||||
- username
|
|
||||||
- password
|
|
||||||
- code
|
|
||||||
- - 测试1
|
|
||||||
- user1
|
|
||||||
- pass1
|
|
||||||
- code1
|
|
||||||
- - 测试2
|
|
||||||
- user2
|
|
||||||
- pass2
|
|
||||||
- code2
|
|
||||||
- - 测试3
|
|
||||||
- user3
|
|
||||||
- pass3
|
|
||||||
- code3
|
|
||||||
- - 测试4
|
|
||||||
- user4
|
|
||||||
- pass4
|
|
||||||
- code4
|
|
||||||
epic: 项目名称:answer
|
epic: 项目名称:answer
|
||||||
feature: 页面状态
|
feature: 页面状态
|
||||||
story: 状态
|
story: 状态
|
||||||
|
|
||||||
02/28/2025 02:08:06 PM [commons.cases] INFO cases.new_case:62 - ddt_title=['查询状态信息', '查询状态信息', '查询状态信息', '查询状态信息']
|
03/02/2025 09:38:14 PM [commons.models] INFO models.ddt:81 - 1,执行这一步
|
||||||
02/28/2025 02:08:06 PM [pytest_result_log] INFO plugin.pytest_runtest_setup:122 - ----------------Start: main.py::TestAPI::test_1_status[查询状态信息0]-----------------
|
03/02/2025 09:38:14 PM [commons.cases] INFO cases.new_case:62 - ddt_title=['查询状态信息']
|
||||||
02/28/2025 02:08:06 PM [commons.cases] INFO cases.test_func:70 - =================================用例开始执行:查询状态信息==================================
|
03/02/2025 09:38:14 PM [pytest_result_log] INFO plugin.pytest_runtest_setup:122 - -----------------Start: main.py::TestAPI::test_1_status[查询状态信息]-----------------
|
||||||
02/28/2025 02:08:06 PM [commons.exchange] INFO exchange.replace:64 - CaseInfo(title='查询状态信息', request={'method': 'get', 'url': '/answer/api/v1/connector/info', 'headers': {'Host': '119.91.19.171:40065', 'Accept-Language': 'en_US', 'Accept': 'application/json, text/plain, */*', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0', 'Referer': 'http://119.91.19.171:40065/users/login', 'Accept-Encoding': 'gzip, deflate'}}, extract={'code': ['json', '$.code', 0], 'msg': ['json', '$.msg', 0]}, validate={'equals': {'状态码等于200': ['Success.', '${msg}']}}, parametrize=[['title', 'username', 'password', 'code'], ['测试1', 'user1', 'pass1', 'code1'], ['测试2', 'user2', 'pass2', 'code2'], ['测试3', 'user3', 'pass3', 'code3'], ['测试4', 'user4', 'pass4', 'code4']], epic='项目名称:answer', feature='页面状态', story='状态')
|
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:70 - =================================用例开始执行:查询状态信息==================================
|
||||||
02/28/2025 02:08:06 PM [commons.cases] INFO cases.test_func:74 - 1,正在注入变量...
|
03/02/2025 09:38:14 PM [commons.exchange] INFO exchange.replace:64 - CaseInfo(title='查询状态信息', request={'method': 'get', 'url': '/answer/api/v1/connector/info', 'headers': {'Host': '119.91.19.171:40065', 'Accept-Language': 'en_US', 'Accept': 'application/json, text/plain, */*', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0', 'Referer': 'http://119.91.19.171:40065/users/login', 'Accept-Encoding': 'gzip, deflate'}}, extract={'msg': ['json', '$.msg', 0]}, validate={'equals': {'状态码等于200': ['Success.', '${msg}']}}, parametrize=[], epic='项目名称:answer', feature='页面状态', story='状态')
|
||||||
02/28/2025 02:08:06 PM [commons.cases] INFO cases.test_func:77 - 2,正在请求接口...
|
03/02/2025 09:38:14 PM [commons.templates] INFO templates.safe_substitute_funcs:51 - mapping更新前: {'msg': 'Success.', 'id': 12}
|
||||||
02/28/2025 02:08:06 PM [requests.session] INFO session.send:36 - 发送请求>>>>>> 接口地址 = GET http://119.91.19.171:40065/answer/api/v1/connector/info
|
03/02/2025 09:38:14 PM [commons.templates] INFO templates.safe_substitute_funcs:54 - mapping更新后: {'msg': 'Success.', 'id': 12, 'int': <class 'int'>, 'float': <class 'float'>, 'bool': <class 'bool'>, 'url_unquote': <function url_unquote at 0x000001E12866A290>, 'str': <function to_string at 0x000001E12866A320>, 'time_str': <function time_str at 0x000001E12866A3B0>, 'add': <function add at 0x000001E12866A440>, 'sql': <function sql at 0x000001E12866A4D0>, 'new_id': <function new_id at 0x000001E12866A560>, 'last_id': <function last_id at 0x000001E12866A5F0>, 'md5': <function md5 at 0x000001E12866A680>, 'base64_encode': <function base64_encode at 0x000001E12866A710>, 'base64_decode': <function base64_decode at 0x000001E12866A7A0>, 'rsa_encode': <function rsa_encode at 0x000001E12866A830>, 'rsa_decode': <function rsa_decode at 0x000001E12866A8C0>}
|
||||||
02/28/2025 02:08:06 PM [requests.session] INFO session.send:37 - 发送请求>>>>>> 请求头 = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': 'application/json, text/plain, */*', 'Connection': 'keep-alive', 'Host': '119.91.19.171:40065', 'Accept-Language': 'en_US', 'Referer': 'http://119.91.19.171:40065/users/login'}
|
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:74 - 1,正在注入变量...
|
||||||
02/28/2025 02:08:06 PM [requests.session] INFO session.send:38 - 发送请求>>>>>> 请求正文 = None
|
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:77 - 2,正在请求接口...
|
||||||
02/28/2025 02:08:06 PM [requests.session] INFO session.send:42 - 接收响应 <<<<<< 状态码 = 200
|
03/02/2025 09:38:14 PM [requests.session] INFO session.send:36 - 发送请求>>>>>> 接口地址 = GET http://119.91.19.171:40065/answer/api/v1/connector/info
|
||||||
02/28/2025 02:08:06 PM [requests.session] INFO session.send:43 - 接收响应 <<<<<< 响应头 = {'Content-Type': 'application/json; charset=utf-8', 'Date': 'Fri, 28 Feb 2025 06:08:07 GMT', 'Content-Length': '63'}
|
03/02/2025 09:38:14 PM [requests.session] INFO session.send:37 - 发送请求>>>>>> 请求头 = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': 'application/json, text/plain, */*', 'Connection': 'keep-alive', 'Host': '119.91.19.171:40065', 'Accept-Language': 'en_US', 'Referer': 'http://119.91.19.171:40065/users/login'}
|
||||||
02/28/2025 02:08:06 PM [requests.session] INFO session.send:44 - 接收响应 <<<<<< 响应正文 = {'code': 200, 'reason': 'base.success', 'msg': 'Success.', 'data': []}
|
03/02/2025 09:38:14 PM [requests.session] INFO session.send:38 - 发送请求>>>>>> 请求正文 = None
|
||||||
02/28/2025 02:08:06 PM [commons.cases] INFO cases.test_func:80 - 3,正在提取变量...
|
03/02/2025 09:38:14 PM [requests.session] INFO session.send:42 - 接收响应 <<<<<< 状态码 = 200
|
||||||
02/28/2025 02:08:06 PM [commons.cases] INFO cases.test_func:86 - 4,正在断言...
|
03/02/2025 09:38:14 PM [requests.session] INFO session.send:43 - 接收响应 <<<<<< 响应头 = {'Content-Type': 'application/json; charset=utf-8', 'Date': 'Sun, 02 Mar 2025 13:38:14 GMT', 'Content-Length': '63'}
|
||||||
02/28/2025 02:08:06 PM [commons.exchange] INFO exchange.replace:64 - CaseInfo(title='查询状态信息', request={'method': 'get', 'url': '/answer/api/v1/connector/info', 'headers': {'Host': '119.91.19.171:40065', 'Accept-Language': 'en_US', 'Accept': 'application/json, text/plain, */*', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0', 'Referer': 'http://119.91.19.171:40065/users/login', 'Accept-Encoding': 'gzip, deflate'}}, extract={'code': ['json', '$.code', 0], 'msg': ['json', '$.msg', 0]}, validate={'equals': {'状态码等于200': ['Success.', '${msg}']}}, parametrize=[['title', 'username', 'password', 'code'], ['测试1', 'user1', 'pass1', 'code1'], ['测试2', 'user2', 'pass2', 'code2'], ['测试3', 'user3', 'pass3', 'code3'], ['测试4', 'user4', 'pass4', 'code4']], epic='项目名称:answer', feature='页面状态', story='状态')
|
03/02/2025 09:38:14 PM [requests.session] INFO session.send:44 - 接收响应 <<<<<< 响应正文 = {'code': 200, 'reason': 'base.success', 'msg': 'Success.', 'data': []}
|
||||||
02/28/2025 02:08:06 PM [pytest_result_log] ERROR plugin.pytest_result_log:190 - test status is FAILED (main.py::TestAPI::test_1_status[查询状态信息0]): TypeError
|
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:80 - 3,正在提取变量...
|
||||||
02/28/2025 02:08:06 PM [pytest_result_log] INFO plugin.pytest_runtest_teardown:128 - -----------------End: main.py::TestAPI::test_1_status[查询状态信息0]------------------
|
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:86 - 4,正在断言...
|
||||||
|
03/02/2025 09:38:14 PM [commons.exchange] INFO exchange.replace:64 - CaseInfo(title='查询状态信息', request={'method': 'get', 'url': '/answer/api/v1/connector/info', 'headers': {'Host': '119.91.19.171:40065', 'Accept-Language': 'en_US', 'Accept': 'application/json, text/plain, */*', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0', 'Referer': 'http://119.91.19.171:40065/users/login', 'Accept-Encoding': 'gzip, deflate'}}, extract={'msg': ['json', '$.msg', 0]}, validate={'equals': {'状态码等于200': ['Success.', '${msg}']}}, parametrize=[], epic='项目名称:answer', feature='页面状态', story='状态')
|
||||||
|
03/02/2025 09:38:14 PM [commons.templates] INFO templates.safe_substitute_funcs:51 - mapping更新前: {'msg': 'Success.', 'id': 12}
|
||||||
|
03/02/2025 09:38:14 PM [commons.templates] INFO templates.safe_substitute_funcs:54 - mapping更新后: {'msg': 'Success.', 'id': 12, 'int': <class 'int'>, 'float': <class 'float'>, 'bool': <class 'bool'>, 'url_unquote': <function url_unquote at 0x000001E12866A290>, 'str': <function to_string at 0x000001E12866A320>, 'time_str': <function time_str at 0x000001E12866A3B0>, 'add': <function add at 0x000001E12866A440>, 'sql': <function sql at 0x000001E12866A4D0>, 'new_id': <function new_id at 0x000001E12866A560>, 'last_id': <function last_id at 0x000001E12866A5F0>, 'md5': <function md5 at 0x000001E12866A680>, 'base64_encode': <function base64_encode at 0x000001E12866A710>, 'base64_decode': <function base64_decode at 0x000001E12866A7A0>, 'rsa_encode': <function rsa_encode at 0x000001E12866A830>, 'rsa_decode': <function rsa_decode at 0x000001E12866A8C0>}
|
||||||
|
03/02/2025 09:38:14 PM [utils.case_validator] INFO case_validator.assert_all:32 - 键:equals,值:{'状态码等于200': ['Success.', 'Success.']}
|
||||||
|
03/02/2025 09:38:14 PM [utils.case_validator] INFO case_validator.assert_all:34 - 获取到的断言:<function validate_equals at 0x000001E12866AB00>
|
||||||
|
03/02/2025 09:38:14 PM [utils.case_validator] INFO case_validator.validate_equals:43 - assert Success. == Success., 状态码等于200执行这段代码
|
||||||
|
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:91 - =================================用例执行结束:查询状态信息==================================
|
||||||
|
03/02/2025 09:38:14 PM [pytest_result_log] INFO plugin.pytest_result_log:190 - test status is PASSED (main.py::TestAPI::test_1_status[查询状态信息]):
|
||||||
|
03/02/2025 09:38:14 PM [pytest_result_log] INFO plugin.pytest_runtest_teardown:128 - ------------------End: main.py::TestAPI::test_1_status[查询状态信息]------------------
|
||||||
|
|||||||
@@ -27,10 +27,11 @@ class CaseValidator:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def assert_all(cls, validate: dict):
|
def assert_all(cls, validate: dict):
|
||||||
|
|
||||||
for assert_type, cases in validate.items():
|
for assert_type, cases in validate.items():
|
||||||
print(f"键:{assert_type},值:{cases}")
|
logger.info(f"键:{assert_type},值:{cases}")
|
||||||
validator = cls.VALIDATORS.get(assert_type)
|
validator = cls.VALIDATORS.get(assert_type)
|
||||||
print(f"获取到的断言:{validator}")
|
logger.info(f"获取到的断言:{validator}")
|
||||||
if not validator:
|
if not validator:
|
||||||
raise KeyError(f"Unsupported validator: {assert_type}")
|
raise KeyError(f"Unsupported validator: {assert_type}")
|
||||||
for msg, (a, b) in cases.items():
|
for msg, (a, b) in cases.items():
|
||||||
@@ -74,5 +75,5 @@ if __name__ == '__main__':
|
|||||||
}
|
}
|
||||||
|
|
||||||
case_validator = CaseValidator()
|
case_validator = CaseValidator()
|
||||||
# print(case_validator.VALIDATORS)
|
print(case_validator.VALIDATORS)
|
||||||
case_validator.assert_all(mock_case.get("validate"))
|
# case_validator.assert_all(mock_case.get("validate"))
|
||||||
|
|||||||
Reference in New Issue
Block a user