refactor(files): 优化项目

- 重构files
- 新增yaml_processor(优化读取文件逻辑)
- 修复bug
This commit is contained in:
2025-03-05 18:11:28 +08:00
parent 698a95ac83
commit b8903798b8
11 changed files with 370 additions and 45 deletions

View File

@@ -48,7 +48,8 @@ class TestAPI:
case_info = CaseInfo(**file) # 校验yaml格式 case_info = CaseInfo(**file) # 校验yaml格式
logger.info(f"case_info={case_info.to_yaml()}") # 把case_info 转成字符串,然后记录日志 logger.info(f"case_info={case_info.to_yaml()}") # 把case_info 转成字符串,然后记录日志
# case_info = {yaml_path.stem:case_info}
# logger.info(f"case_info_dict={case_info}")
case_func = cls.new_case(case_info) # 从yaml格式转换为pytest格式 case_func = cls.new_case(case_info) # 从yaml格式转换为pytest格式
print(yaml_path.stem) print(yaml_path.stem)
setattr(cls, f"{yaml_path.stem}", case_func) # 把pytest格式添加到类中 setattr(cls, f"{yaml_path.stem}", case_func) # 把pytest格式添加到类中

View File

@@ -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"E:\PyP\InterfaceAutoTest\extract.yaml") exchanger = Exchange(r"D:\CNWei\CNW\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)

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env python
# coding=utf-8
"""
@author: CNWei
@Software: PyCharm
@contact: t6i888@163.com
@file: __init__.py
@date: 2025/3/4 17:23
@desc:
"""

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env python
# coding=utf-8
"""
@author: CNWei
@Software: PyCharm
@contact: t6i888@163.com
@file: base
@date: 2025/3/4 17:23
@desc:
"""
import abc
class BaseFileProcessor(abc.ABC): # 使用 abc 模块定义抽象基类
"""
文件处理器的抽象基类。
定义了所有子类必须实现的方法。
"""
@abc.abstractmethod
def load(self):
"""加载."""
pass
@abc.abstractmethod
def to_string(self) -> str:
"""将文件内容转换为字符串。"""
pass
@abc.abstractmethod
def to_dict(self, data: str) -> dict:
"""将文件内容转换为字典。"""
pass
@abc.abstractmethod
def save(self, new_filepath=None):
"""将数据保存."""
pass

View File

@@ -0,0 +1,176 @@
#!/usr/bin/env python
# coding=utf-8
"""
@author: CNWei
@Software: PyCharm
@contact: t6i888@163.com
@file: yaml_processor
@date: 2025/3/4 17:28
@desc:
"""
import logging
from typing import Union
from dataclasses import dataclass, asdict, field
from pathlib import Path
import yaml
from base import BaseFileProcessor
logger = logging.getLogger(__name__)
class YamlFile(BaseFileProcessor,dict):
"""
用于处理 YAML 文件的类,继承自 dict。
提供了从文件加载、保存到文件、转换为字符串和从字符串转换的功能,
并可以直接像字典一样访问 YAML 数据。
"""
def __init__(self, filepath: Union[str, Path], data: Union[dict, None] = None):
"""
初始化 YamlFile 对象。
Args:
filepath: YAML 文件的路径 (可以是字符串或 pathlib.Path 对象).
data: 可选的初始数据字典。如果提供,则用该字典初始化 YamlFile。
如果不提供,则尝试从 filepath 加载数据。
"""
super().__init__() # 初始化父类 dict
self.filepath: Path = Path(filepath) # 确保 filepath 是 Path 对象
if data is not None:
self.update(data) # 如果提供了初始数据,则更新字典
else:
self.load() # 否则,尝试从文件加载
def load(self) -> None:
"""
从 YAML 文件加载数据并更新字典。
如果文件不存在或加载失败,则清空字典并记录警告/错误。
"""
self.clear() # 清空现有数据
if self.filepath.exists():
try:
with open(self.filepath, "r", encoding="utf-8") as f:
loaded_data = yaml.safe_load(f) or {}
self.update(loaded_data) # 使用加载的数据更新字典
except yaml.YAMLError as e:
logger.error(f"加载 YAML 文件 {self.filepath} 时出错: {e}")
# 保持字典为空 (已在开头 clear)
else:
logger.warning(f"文件 {self.filepath} 不存在, 字典保持为空.")
# 保持字典为空 (已在开头 clear)
def to_string(self) -> str:
"""
将字典 (自身) 转换为 YAML 格式的字符串。
Returns:
YAML 格式的字符串。
"""
try:
return yaml.safe_dump(
dict(self), # 使用dict转换为标准的字典
allow_unicode=True,
sort_keys=False,
default_flow_style=False
)
except TypeError as e:
logger.error(f"将数据转换为 YAML 字符串时出错: {e}")
return ""
def to_dict(self, data: str) -> None:
"""
将 YAML 格式的字符串转换为字典,并更新当前字典的内容.
Args:
data: YAML 格式的字符串。
"""
try:
loaded_data = yaml.safe_load(data) or {}
self.clear()
self.update(loaded_data) # 清空并更新
except yaml.YAMLError as e:
logger.error(f"将 YAML 字符串转换为字典时出错: {e}")
self.clear() # 出错时也清空
def save(self, new_filepath: Union[str, Path, None] = None):
"""
将字典数据 (自身) 保存到 YAML 文件。
Args:
new_filepath: 可选参数,指定新的文件路径。如果为 None则覆盖原文件。
"""
filepath = Path(new_filepath) if new_filepath else self.filepath
try:
with open(filepath, "w", encoding="utf-8") as f:
yaml.safe_dump(
dict(self), # 使用dict转换为标准的字典
stream=f,
allow_unicode=True,
sort_keys=False,
default_flow_style=False
)
except (TypeError, OSError) as e:
logger.error(f"保存 YAML 文件 {filepath} 时出错: {e}")
if __name__ == '__main__':
# 示例用法
yaml_path = r'D:\CNWei\CNW\InterfaceAutoTest\TestCases\test_1_user.yaml' # 你的 YAML 文件路径
yaml_file = YamlFile(yaml_path)
print(yaml_file)
print(type(yaml_file))
# # 直接像字典一样访问数据
# print("加载的数据:", yaml_file) # 直接打印对象,就是打印字典内容
# print("title:", yaml_file.get("title")) # 使用 get 方法
# if "title" in yaml_file: # 使用 in 检查键
# print("原始title:", yaml_file["title"]) # 使用方括号访问
# yaml_file["title"] = "新的标题" # 使用方括号修改
# print("修改后的title:", yaml_file["title"])
# #
# yaml_file["new_key"] = "new_value" # 添加新的键值对
#
# # 将字典转换为 YAML 字符串
# yaml_string = yaml_file.to_string()
# print("\nYAML 字符串:", yaml_string)
# #
# # 将 YAML 字符串转换回字典 (并更新 yaml_file)
# yaml_file.to_dict(yaml_string)
# print("\n从字符串加载的数据:", yaml_file)
#
# # 保存修改后的数据 (覆盖原文件)
# yaml_file.save()
#
# # 保存到新文件
# new_yaml_path = r'D:\CNWei\CNW\InterfaceAutoTest\TestCases\test_1_user_new.yaml'
# yaml_file.save(new_filepath=new_yaml_path)
# 测试从字符串初始化
# yaml_string2 = """
# name: Test User
# age: 30
# """
# yaml_file2 = YamlFile("test2.yaml", data=yaml.safe_load(yaml_string2)) # 从字符串初始化
# print("\n从字符串初始化的 YamlFile:", yaml_file2)
# yaml_file2.save() # 保存到 test2.yaml
#
# 测试文件不存在的情形
# non_existent_file = YamlFile("non_existent_file.yaml")
# print("\n加载不存在的文件:", non_existent_file) # 应该打印空字典 {}
# non_existent_file['a'] = 1 # 可以直接添加
# print("\n加载不存在的文件:", non_existent_file)
# if __name__ == '__main__':
# from commons.models import CaseInfo
#
# yaml_path = r'D:\CNWei\CNW\InterfaceAutoTest\TestCases\test_1_user.yaml'
# yaml_file = YamlFile(yaml_path)
# print(yaml_file.load())
# # yaml_file.load()
# # case_info = CaseInfo(**yaml_file)
# # print(case_info)
# # yaml_file["title"] = "查询用户信息"
# # yaml_file.save()

View File

@@ -10,7 +10,8 @@
@desc: 读取和保存yaml文件 @desc: 读取和保存yaml文件
""" """
import logging import logging
from dataclasses import dataclass, asdict, field
from pathlib import Path
import yaml import yaml
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -18,24 +19,42 @@ logger = logging.getLogger(__name__)
class YamlFile(dict): class YamlFile(dict):
def __init__(self, path): def __init__(self, path):
super().__init__() super().__init__() # 初始化父类 dict
self.path = path self.path = Path(path)
self.load() self.load() # 链式初始化加载
def load(self): def load(self):
if self.path.exists():
with open(self.path, "r", encoding="utf-8") as f: with open(self.path, "r", encoding="utf-8") as f:
data = yaml.safe_load(f) # 字典 data = yaml.safe_load(f) or {} # 加载数据,空文件返回空字典
if data: self.clear() # 清空当前实例
self.update(data) # 把两个字段的内容合并 self.update(data) # 更新字典内容
else:
logger.warning(f"File {self.path} not found, initialized empty.")
return self # 链式调用
def to_yaml(self) -> str:
return yaml.safe_dump(
dict(self),
allow_unicode=True,
sort_keys=False
)
@classmethod
def by_yaml(cls, yaml_str):
data = yaml.safe_load(yaml_str) or {}
return cls({**data}) # 通过类方法创建实例
def save(self): def save(self):
with open(self.path, "w", encoding="utf-8") as f: with open(self.path, "w", encoding="utf-8") as f:
yaml.safe_dump( yaml.safe_dump(
dict(self), dict(self), # 直接 dump 实例本身(已继承 dict
stream=f, stream=f,
allow_unicode=True, # allow_unicode使用unicode编码正常显示中文 allow_unicode=True,
sort_keys=False # sort_keys保持原有排序 sort_keys=False
) )
return self # 链式调用
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -15,7 +15,7 @@ import time
import urllib.parse import urllib.parse
import hashlib import hashlib
from commons.databases import db # from commons.databases import db
from commons.files import YamlFile from commons.files import YamlFile
from commons import settings from commons import settings

View File

@@ -1,2 +1,7 @@
msg: Success. name: 张三
id: 12 age: '18'
data:
- 3
- 4
- 5
aaa: null

View File

@@ -1,5 +1,5 @@
03/02/2025 09:38:14 PM [commons.cases] INFO cases.find_yaml_case:45 - 加载文件:E:\PyP\InterfaceAutoTest\TestCases\answer\test_1_status.yaml 03/03/2025 05:34:28 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:50 - case_info=title: 查询状态信息 03/03/2025 05:34:28 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
@@ -26,29 +26,29 @@ epic: 项目名称answer
feature: 页面状态 feature: 页面状态
story: 状态 story: 状态
03/02/2025 09:38:14 PM [commons.models] INFO models.ddt:81 - 1执行这一步 03/03/2025 05:34:28 PM [commons.models] INFO models.ddt:81 - 1执行这一步
03/02/2025 09:38:14 PM [commons.cases] INFO cases.new_case:62 - ddt_title=['查询状态信息'] 03/03/2025 05:34:28 PM [commons.cases] INFO cases.new_case:63 - ddt_title=['查询状态信息']
03/02/2025 09:38:14 PM [pytest_result_log] INFO plugin.pytest_runtest_setup:122 - -----------------Start: main.py::TestAPI::test_1_status[查询状态信息]----------------- 03/03/2025 05:34:28 PM [pytest_result_log] INFO plugin.pytest_runtest_setup:122 - -----------------Start: main.py::TestAPI::test_1_status[查询状态信息]-----------------
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:70 - =================================用例开始执行:查询状态信息================================== 03/03/2025 05:34:28 PM [commons.cases] INFO cases.test_func:71 - =================================用例开始执行:查询状态信息==================================
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/03/2025 05:34:28 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/03/2025 05:34:28 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/03/2025 05:34:28 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 0x00000299E6AAC0D0>, 'str': <function to_string at 0x00000299E6AAC160>, 'time_str': <function time_str at 0x00000299E6AAC1F0>, 'add': <function add at 0x00000299E6AAC280>, 'sql': <function sql at 0x00000299E6AAC310>, 'new_id': <function new_id at 0x00000299E6AAC3A0>, 'last_id': <function last_id at 0x00000299E6AAC430>, 'md5': <function md5 at 0x00000299E6AAC4C0>, 'base64_encode': <function base64_encode at 0x00000299E6AAC550>, 'base64_decode': <function base64_decode at 0x00000299E6AAC5E0>, 'rsa_encode': <function rsa_encode at 0x00000299E6AAC670>, 'rsa_decode': <function rsa_decode at 0x00000299E6AAC700>}
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:74 - 1正在注入变量... 03/03/2025 05:34:28 PM [commons.cases] INFO cases.test_func:75 - 1正在注入变量...
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:77 - 2正在请求接口... 03/03/2025 05:34:28 PM [commons.cases] INFO cases.test_func:78 - 2正在请求接口...
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 03/03/2025 05:34:28 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 [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/03/2025 05:34:28 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 [requests.session] INFO session.send:38 - 发送请求>>>>>> 请求正文 = None 03/03/2025 05:34:28 PM [requests.session] INFO session.send:38 - 发送请求>>>>>> 请求正文 = None
03/02/2025 09:38:14 PM [requests.session] INFO session.send:42 - 接收响应 <<<<<< 状态码 = 200 03/03/2025 05:34:28 PM [requests.session] INFO session.send:42 - 接收响应 <<<<<< 状态码 = 200
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'} 03/03/2025 05:34:28 PM [requests.session] INFO session.send:43 - 接收响应 <<<<<< 响应头 = {'Content-Type': 'application/json; charset=utf-8', 'Date': 'Mon, 03 Mar 2025 09:34:29 GMT', 'Content-Length': '63'}
03/02/2025 09:38:14 PM [requests.session] INFO session.send:44 - 接收响应 <<<<<< 响应正文 = {'code': 200, 'reason': 'base.success', 'msg': 'Success.', 'data': []} 03/03/2025 05:34:28 PM [requests.session] INFO session.send:44 - 接收响应 <<<<<< 响应正文 = {'code': 200, 'reason': 'base.success', 'msg': 'Success.', 'data': []}
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:80 - 3正在提取变量... 03/03/2025 05:34:28 PM [commons.cases] INFO cases.test_func:81 - 3正在提取变量...
03/02/2025 09:38:14 PM [commons.cases] INFO cases.test_func:86 - 4正在断言... 03/03/2025 05:34:28 PM [commons.cases] INFO cases.test_func:87 - 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/03/2025 05:34:28 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/03/2025 05:34:28 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/03/2025 05:34:28 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 0x00000299E6AAC0D0>, 'str': <function to_string at 0x00000299E6AAC160>, 'time_str': <function time_str at 0x00000299E6AAC1F0>, 'add': <function add at 0x00000299E6AAC280>, 'sql': <function sql at 0x00000299E6AAC310>, 'new_id': <function new_id at 0x00000299E6AAC3A0>, 'last_id': <function last_id at 0x00000299E6AAC430>, 'md5': <function md5 at 0x00000299E6AAC4C0>, 'base64_encode': <function base64_encode at 0x00000299E6AAC550>, 'base64_decode': <function base64_decode at 0x00000299E6AAC5E0>, 'rsa_encode': <function rsa_encode at 0x00000299E6AAC670>, 'rsa_decode': <function rsa_decode at 0x00000299E6AAC700>}
03/02/2025 09:38:14 PM [utils.case_validator] INFO case_validator.assert_all:32 - 键equals{'状态码等于200': ['Success.', 'Success.']} 03/03/2025 05:34:28 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/03/2025 05:34:28 PM [utils.case_validator] INFO case_validator.assert_all:34 - 获取到的断言:<function validate_equals at 0x00000299E6AAC940>
03/02/2025 09:38:14 PM [utils.case_validator] INFO case_validator.validate_equals:43 - assert Success. == Success., 状态码等于200执行这段代码 03/03/2025 05:34:28 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/03/2025 05:34:28 PM [commons.cases] INFO cases.test_func:92 - =================================用例执行结束:查询状态信息==================================
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/03/2025 05:34:28 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[查询状态信息]------------------ 03/03/2025 05:34:28 PM [pytest_result_log] INFO plugin.pytest_runtest_teardown:128 - ------------------End: main.py::TestAPI::test_1_status[查询状态信息]------------------

View File

@@ -21,6 +21,12 @@ from commons.models import CaseInfo
class CaseParser: class CaseParser:
@staticmethod @staticmethod
def to_yaml(case_data: dict) -> str: def to_yaml(case_data: dict) -> str:
try:
CaseInfo(**case_data)
except TypeError as error:
logging.error(error)
raise error
return yaml.safe_dump(case_data, allow_unicode=True, sort_keys=False) return yaml.safe_dump(case_data, allow_unicode=True, sort_keys=False)
@staticmethod @staticmethod
@@ -38,5 +44,5 @@ if __name__ == '__main__':
case_parser = CaseParser() case_parser = CaseParser()
case_data_ = case_parser.to_yaml(data) case_data_ = case_parser.to_yaml(data)
# print(case_data_) # print(case_data_)
case_parser.from_yaml(case_data_) # case_parser.from_yaml(case_data_)
# print(type(case_data_)) # print(type(case_data_))

68
utils/data_driver.py Normal file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env python
# coding=utf-8
"""
@author: CNWei
@Software: PyCharm
@contact: t6i888@163.com
@file: data_driver
@date: 2025/3/3 10:56
@desc:
"""
from commons.models import CaseInfo
from commons.templates import Template
class DataDriver:
@staticmethod
def generate_cases(case_info) -> list:
if not case_info.get("parametrize"):
return [case_info]
cases = []
args_names = case_info.get("parametrize")[0]
for args_values in case_info.get("parametrize")[1:]:
print(args_values)
context = dict(zip(args_names, args_values))
print(context)
rendered = Template(CaseInfo(**case_info).to_yaml()).render(context)
cases.append({args_names[0]:CaseInfo(**case_info).by_yaml(rendered)})
return cases
if __name__ == '__main__':
mock_case_info = {
"case_info0": {
"feature": "页面状态",
"story": "状态",
"title": "查询状态信息",
"request": "",
"extract": "",
"validate": "",
"parametrize": [[ "title","username","password","msg" ] ,[ "测试1","user1","pass1","200" ] ,[ "测试2","user2","pass2","300" ]]
},
"case_info1": {
"feature": "页面状态",
"story": "状态",
"title": "查询状态信息",
"request": "",
"extract": "",
"validate": "",
"parametrize": [1,2,3]
},
"case_info2": {
"feature": "页面状态",
"story": "状态",
"title": "查询状态信息",
"request": "",
"extract": "",
"validate": "",
"parametrize": [1,2,3]
}
}
dd = DataDriver()
cases = dd.generate_cases(mock_case_info.get("case_info0"))
print(cases)