将原有测试用例数据在data的目录结构平移后生成测试方法,例如原有测试数据路径是:data/gitlink/project/test_login_demo.yaml, 生成测试方法的路径是:test_case/test_auto_case/gitlink/project/test_login_demo.py
This commit is contained in:
+139
-101
@@ -4,15 +4,17 @@
|
||||
# @File : case_fun_handle.py
|
||||
# @Software: PyCharm
|
||||
# @Desc:
|
||||
|
||||
# 标准库导入
|
||||
import os
|
||||
from string import Template
|
||||
import datetime
|
||||
# 第三方库导入
|
||||
from xpinyin import Pinyin # 纯 Python 编写的中文字符串拼音转换模块,不需要依赖外部程序和词库。
|
||||
from loguru import logger
|
||||
# 本地应用/模块导入
|
||||
from common_utils.excel_handle import ExcelHandle
|
||||
from common_utils.yaml_handle import YamlHandle
|
||||
from common_utils.files_handle import get_files
|
||||
from common_utils.files_handle import get_files, get_relative_path
|
||||
from config.models import CaseFileType
|
||||
from config.settings import CASE_FILE_TYPE
|
||||
from config.path_config import DATA_DIR, CASE_TEMPLATE_DIR, AUTO_CASE_DIR
|
||||
@@ -26,138 +28,174 @@ from case_utils.case_data_analysis import CaseDataCheck
|
||||
"""
|
||||
|
||||
|
||||
def generate_case_from_excel(files: list):
|
||||
def handle_excel_data(file):
|
||||
"""
|
||||
读取excel用例数据生成测试用例
|
||||
"""
|
||||
for file in files:
|
||||
if os.path.isfile(file):
|
||||
# 读取excel文件中的用例数据,存储到data中
|
||||
if os.path.isfile(file):
|
||||
# 读取xlsx/xls文件中的用例数据,存储到data中
|
||||
data = ExcelHandle(file).read()
|
||||
# logger.debug(f"从{file}中读取到的用例数据是:{data}")
|
||||
for index, v in enumerate(data):
|
||||
excel_case = {}
|
||||
# 将excel读取到的用例数据,适配allure格式
|
||||
"""
|
||||
表单名称以短横线隔开的情况下,左边部分作为allure_epic, 右边部分作为allure_feature以及allure_story。
|
||||
否则,表单名称全部作为allure_epic,allure_feature,allure_story
|
||||
"""
|
||||
if "-" in v["sheet_name"]:
|
||||
excel_case["case_common"] = {
|
||||
"allure_epic": v["sheet_name"].split("-")[0],
|
||||
"allure_feature": v["sheet_name"].split("-")[1],
|
||||
"allure_story": v["sheet_name"].split("-")[1]
|
||||
}
|
||||
else:
|
||||
excel_case["case_common"] = {
|
||||
"allure_epic": v["sheet_name"],
|
||||
"allure_feature": v["sheet_name"],
|
||||
"allure_story": v["sheet_name"]
|
||||
}
|
||||
# 处理excel用例数据
|
||||
for case in v["data"]:
|
||||
excel_case[case["id"]] = case
|
||||
# 检查用例数据是否符合规范
|
||||
tested_case = CaseDataCheck().case_process(excel_case)
|
||||
# 生成测试方法
|
||||
"""
|
||||
由于excel涉及到多个表单,每一个表单都会生成一个测试方法。因此会将表单名称的首字母拼接到测试方法上。
|
||||
excel名称:test_demo
|
||||
例如表单名称:"GitLink-登录模块" 或 "登录模块",都是取关键字"登录模块"首字母
|
||||
测试文件:test_demo_dl.py
|
||||
测试方法名称: TestDemoDl.test_demo_dl
|
||||
"""
|
||||
pin_yin = Pinyin()
|
||||
_name = pin_yin.get_initials(excel_case["case_common"]["allure_feature"], "").lower()
|
||||
gen_case_file(filename=os.path.splitext(os.path.basename(file))[0] + "_" + _name,
|
||||
case_template_path=CASE_TEMPLATE_DIR,
|
||||
case_common=excel_case["case_common"], case_data=tested_case,
|
||||
target_case_path=AUTO_CASE_DIR)
|
||||
else:
|
||||
logger.error(f"{file}不是一个正确的文件路径!")
|
||||
data = ExcelHandle(file).read()
|
||||
for index, v in enumerate(data):
|
||||
excel_case = {}
|
||||
"""
|
||||
将excel读取到的用例数据,适配allure格式
|
||||
表单名称以短横线隔开的情况下,左边部分作为allure_epic, 右边部分作为allure_feature以及allure_story。
|
||||
否则,表单名称全部作为allure_epic,allure_feature,allure_story
|
||||
"""
|
||||
if "-" in v["sheet_name"]:
|
||||
excel_case["case_common"] = {
|
||||
"allure_epic": v["sheet_name"].split("-")[0],
|
||||
"allure_feature": v["sheet_name"].split("-")[1],
|
||||
"allure_story": v["sheet_name"].split("-")[1]
|
||||
}
|
||||
else:
|
||||
excel_case["case_common"] = {
|
||||
"allure_epic": v["sheet_name"],
|
||||
"allure_feature": v["sheet_name"],
|
||||
"allure_story": v["sheet_name"]
|
||||
}
|
||||
# 处理excel用例数据
|
||||
for case in v["data"]:
|
||||
excel_case[case["id"]] = case
|
||||
# 检查用例数据是否符合规范
|
||||
tested_case = CaseDataCheck().case_process(excel_case)
|
||||
# 生成测试方法
|
||||
"""
|
||||
由于excel涉及到多个表单,每一个表单都会生成一个测试方法。因此会将表单名称的首字母拼接到测试方法上。
|
||||
excel名称:test_demo
|
||||
例如表单名称:"GitLink-登录模块" 或 "登录模块",都是取关键字"登录模块"首字母
|
||||
测试文件:test_demo_dl.py
|
||||
测试方法名称: TestDemoDl.test_demo_dl
|
||||
"""
|
||||
pin_yin = Pinyin()
|
||||
_name = pin_yin.get_initials(excel_case["case_common"]["allure_feature"], "").lower()
|
||||
if os.path.samefile(DATA_DIR, os.path.dirname(file)):
|
||||
# 用例文件的直接父级目录是DATA_DIR,则直接在AUTO_CASE_DIR下生成测试用例方法
|
||||
gen_case_file(
|
||||
filename=os.path.splitext(os.path.basename(file))[0] + "_" + _name,
|
||||
case_template_path=CASE_TEMPLATE_DIR,
|
||||
case_common=excel_case["case_common"],
|
||||
case_data=tested_case,
|
||||
target_case_path=AUTO_CASE_DIR
|
||||
)
|
||||
else:
|
||||
# 用例文件的直接父级目录不是DATA_DIR, 则保留其直接父级目录,再在AUTO_CASE_DIR下生成测试用例方法
|
||||
gen_case_file(
|
||||
filename=os.path.splitext(os.path.basename(file))[0] + "_" + _name,
|
||||
case_template_path=CASE_TEMPLATE_DIR,
|
||||
case_common=excel_case["case_common"],
|
||||
case_data=tested_case,
|
||||
target_case_path=os.path.join(AUTO_CASE_DIR,
|
||||
get_relative_path(file_path=file, directory_path=DATA_DIR))
|
||||
)
|
||||
return True
|
||||
else:
|
||||
logger.error(f"{file}不是一个正确的文件路径!")
|
||||
return False
|
||||
|
||||
|
||||
def generate_case_from_yaml(files: list):
|
||||
def handle_yaml_data(file):
|
||||
"""
|
||||
读取yaml用例数据生成测试用例
|
||||
"""
|
||||
for file in files:
|
||||
# 从yaml/yml中读取用例数据
|
||||
if os.path.isfile(file):
|
||||
# 读取yaml/yml文件中的用例数据,存储到data中
|
||||
yaml_data = YamlHandle(file).read_yaml
|
||||
# logger.debug(f"从{file}中读取到的用例数据是:{yaml_data}")
|
||||
# 检查用例数据是否符合规范
|
||||
tested_case = CaseDataCheck().case_process(yaml_data)
|
||||
# 生成测试方法
|
||||
gen_case_file(filename=os.path.splitext(os.path.basename(file))[0], case_template_path=CASE_TEMPLATE_DIR,
|
||||
case_common=yaml_data["case_common"], case_data=tested_case,
|
||||
target_case_path=AUTO_CASE_DIR)
|
||||
if os.path.isfile(file):
|
||||
# 读取yaml/yml文件中的用例数据,存储到data中
|
||||
yaml_data = YamlHandle(file).read_yaml
|
||||
# 检查用例数据是否符合规范
|
||||
tested_case = CaseDataCheck().case_process(yaml_data)
|
||||
if os.path.samefile(DATA_DIR, os.path.dirname(file)):
|
||||
gen_case_file(
|
||||
# 用例文件的直接父级目录是DATA_DIR,则直接在AUTO_CASE_DIR下生成测试用例方法
|
||||
filename=os.path.splitext(os.path.basename(file))[0],
|
||||
case_template_path=CASE_TEMPLATE_DIR,
|
||||
case_common=yaml_data["case_common"],
|
||||
case_data=tested_case,
|
||||
target_case_path=AUTO_CASE_DIR
|
||||
)
|
||||
else:
|
||||
logger.error(f"{file}不是一个正确的文件路径!")
|
||||
# 用例文件的直接父级目录不是DATA_DIR, 则保留其直接父级目录,再在AUTO_CASE_DIR下生成测试用例方法
|
||||
os.makedirs(os.path.dirname(file), exist_ok=True)
|
||||
gen_case_file(
|
||||
filename=os.path.splitext(os.path.basename(file))[0],
|
||||
case_template_path=CASE_TEMPLATE_DIR,
|
||||
case_common=yaml_data["case_common"],
|
||||
case_data=tested_case,
|
||||
target_case_path=os.path.join(AUTO_CASE_DIR,
|
||||
get_relative_path(file_path=file, directory_path=DATA_DIR))
|
||||
)
|
||||
return True
|
||||
else:
|
||||
logger.error(f"{file}不是一个正确的文件路径!")
|
||||
return False
|
||||
|
||||
|
||||
def generate_cases():
|
||||
"""
|
||||
根据配置文件,从指定类型文件中读取所有用例数据,并自动生成测试用例
|
||||
"""
|
||||
# 判断配置文件里面CASE_DATA_TYPE,判断用例数据是从excel还是yaml文件中读取
|
||||
# 从excel中读取用例数据
|
||||
excel_files = []
|
||||
yaml_files = []
|
||||
if CASE_FILE_TYPE == CaseFileType.EXCEL.value:
|
||||
# 在用例数据"DATA_DIR"目录中寻找后缀是xlsx, xls的文件
|
||||
files = get_files(target=DATA_DIR, start="test_", end=".xlsx") \
|
||||
excel_files = get_files(target=DATA_DIR, start="test_", end=".xlsx") \
|
||||
+ get_files(target=DATA_DIR, start="test_", end=".xls")
|
||||
# 自动生成测试用例
|
||||
generate_case_from_excel(files)
|
||||
# 从yaml中读取用例数据
|
||||
elif CASE_FILE_TYPE == CaseFileType.YAML.value:
|
||||
# 在用例数据"DATA_DIR"目录中寻找后缀是yaml, yml的文件
|
||||
files = get_files(target=DATA_DIR, start="test_", end=".yaml") \
|
||||
+ get_files(target=DATA_DIR, start="test_", end=".yml")
|
||||
# 自动生成测试用例
|
||||
generate_case_from_yaml(files)
|
||||
else:
|
||||
# 在用例数据"DATA_DIR"目录中寻找后缀是xlsx,xls, yaml, yml的文件
|
||||
excel_files = get_files(target=DATA_DIR, start="test_", end=".xlsx") \
|
||||
+ get_files(target=DATA_DIR, start="test_", end=".xls")
|
||||
yaml_files = get_files(target=DATA_DIR, start="test_", end=".yaml") \
|
||||
+ get_files(target=DATA_DIR, start="test_", end=".yml")
|
||||
# 自动生成测试用例
|
||||
generate_case_from_excel(excel_files)
|
||||
generate_case_from_yaml(yaml_files)
|
||||
+ get_files(target=DATA_DIR, start="test_", end=".yml")
|
||||
elif CASE_FILE_TYPE == CaseFileType.ALL.value:
|
||||
# 在用例数据"DATA_DIR"目录中寻找后缀是xlsx,xls, yaml, yml的文件
|
||||
excel_files = get_files(target=DATA_DIR, start="test_", end=".xlsx") + get_files(target=DATA_DIR, start="test_",
|
||||
end=".xls")
|
||||
yaml_files = get_files(target=DATA_DIR, start="test_", end=".yaml") + get_files(target=DATA_DIR, start="test_", end=".yml")
|
||||
else:
|
||||
logger.error(f"{CASE_FILE_TYPE}不在CaseFileType内,不能自动生成用例!")
|
||||
# 自动生成测试用例
|
||||
for file in excel_files:
|
||||
handle_excel_data(file=file)
|
||||
for file in yaml_files:
|
||||
handle_yaml_data(file=file)
|
||||
|
||||
|
||||
def gen_case_file(filename, case_template_path, case_common, case_data, target_case_path):
|
||||
"""
|
||||
根据测试用例文件(yaml/yml/xlsx/xls),以及事先定义的测试用例模板,实际用例数据,生成测试用例方法(.py)
|
||||
:param filename: 测试用例文件(yaml/yml/xlsx/xls)的名称,用作生成测试用例类名,方法名
|
||||
:param case_template_path: 测试用例模板的绝对路径
|
||||
:param case_common: 用例公共参数
|
||||
:param case_data: 实际用例数据
|
||||
:param target_case_path: 测试用例方法(.py)的绝对路径
|
||||
根据测试用例文件(yaml/yml/xlsx/xls),以及事先定义的测试用例模板,实际用例数据,生成测试用例方法(.py)
|
||||
:param filename: 测试用例文件(yaml/yml/xlsx/xls)的名称,用作生成测试用例类名,方法名
|
||||
:param case_template_path: 测试用例模板的绝对路径
|
||||
:param case_common: 用例公共参数
|
||||
:param case_data: 实际用例数据
|
||||
:param target_case_path: 测试用例方法(.py)的绝对路径
|
||||
"""
|
||||
# 如果自动生成用例的目录不存在则自动创建一个
|
||||
if not os.path.exists(AUTO_CASE_DIR):
|
||||
os.makedirs(AUTO_CASE_DIR)
|
||||
"""
|
||||
string.Template是将一个string设置为模板,通过替换变量的方法,最终得到想要的string。
|
||||
"""
|
||||
if not os.path.exists(target_case_path):
|
||||
"""
|
||||
exist_ok=True 是一个可选参数,用于指定在目录已经存在的情况下是否忽略错误。
|
||||
如果设置为 True,则不论目录是否已存在,os.makedirs 都不会报错;如果设置为 False(默认值),则在目录已存在时会引发 FileExistsError 异常。
|
||||
"""
|
||||
os.makedirs(target_case_path, exist_ok=True)
|
||||
# 定义生成的测试用例的模板
|
||||
with open(file=case_template_path, mode="r", encoding="utf-8") as f:
|
||||
case_template = f.read()
|
||||
# 将用例数据的名称作为测试用例文件名称, 如test_login_demo
|
||||
func_name = filename
|
||||
# 方法名test_demo的类名是TestDemo
|
||||
class_name = "".join([word.capitalize() for word in func_name.split("_")])
|
||||
# 定义生成的测试用例的模板
|
||||
with open(file=case_template_path, mode="r", encoding="utf-8") as f:
|
||||
case_template = f.read()
|
||||
# 根据模板,生成测试用例方法
|
||||
my_case = Template(case_template).safe_substitute({"allure_epic": case_common["allure_epic"],
|
||||
"allure_feature": case_common["allure_feature"],
|
||||
"allure_story": case_common["allure_story"],
|
||||
"case_data": case_data,
|
||||
"func_title": func_name,
|
||||
"class_title": class_name,
|
||||
"now": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
|
||||
"""
|
||||
string.Template是将一个string设置为模板,通过替换变量的方法,最终得到想要的string。
|
||||
"""
|
||||
my_case = Template(case_template).safe_substitute(
|
||||
{
|
||||
"allure_epic": case_common["allure_epic"],
|
||||
"allure_feature": case_common["allure_feature"],
|
||||
"allure_story": case_common["allure_story"],
|
||||
"case_data": case_data,
|
||||
"func_title": func_name,
|
||||
"class_title": class_name,
|
||||
"now": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
)
|
||||
|
||||
# 将测试用例方法写入py文件中
|
||||
with open(os.path.join(target_case_path, func_name + '.py'), "w", encoding="utf-8") as fp:
|
||||
fp.write(my_case)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
# @File : files_handle.py
|
||||
# @Software: PyCharm
|
||||
# @Desc: 处理文件相关操作
|
||||
|
||||
# 标准库导入
|
||||
import os
|
||||
import zipfile
|
||||
import shutil
|
||||
@@ -146,3 +148,16 @@ def get_file_field(file_path):
|
||||
with open(file_path, 'rb') as f:
|
||||
file_content = f.read()
|
||||
return (file_name, file_content)
|
||||
|
||||
|
||||
def get_relative_path(file_path, directory_path):
|
||||
"""
|
||||
os.path.relpath()是Python中os.path模块提供的一个函数,用于计算两个路径之间的相对路径。
|
||||
例如:file_path=data/gitlink/project/test_login_demo.yaml, directory_path=data, 将返回/gitlink/project
|
||||
:param: file_path: 文件路径
|
||||
:param: directory_path: 相对于目录路径
|
||||
"""
|
||||
# 获取file_path相对于directory_path的相对路径
|
||||
relative_path = os.path.relpath(os.path.abspath(file_path), os.path.abspath(directory_path))
|
||||
# 如果相对路径中包含文件名,则去除文件名部分并返回
|
||||
return os.path.dirname(relative_path)
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@
|
||||
# @Desc: 项目配置文件
|
||||
|
||||
# ------------------------------------ 配置信息 ----------------------------------------------------#
|
||||
# 0代表执行Excel和yaml两种格式的用例, 1 代表 yaml文件,2 用例代表Excel用例
|
||||
CASE_FILE_TYPE = 0
|
||||
# 0代表执行Excel和yaml两种格式的用例, 1 代表 yaml文件,2 用例代表Excel用例, 其他数值将不自动生成用例,仅能执行手动编写的用例
|
||||
CASE_FILE_TYPE = 3
|
||||
|
||||
# 0表示默认不发送任何通知, 1代表钉钉通知,2代表企业微信通知, 3代表邮件通知, 4代表所有途径都发送通知
|
||||
SEND_RESULT_TYPE = 0
|
||||
|
||||
Reference in New Issue
Block a user