优化代码,增加更新测试用例功能

This commit is contained in:
2026-06-04 13:53:31 +08:00
parent fb86198565
commit 83a425c235
9 changed files with 247 additions and 88 deletions
+2 -5
View File
@@ -14,6 +14,8 @@ from .base import DataLog, SignalData, ExcelDataResult
from .mil_read_data_excel import read_excel_data, get_data_log, ExcelReaderConfig
from .mil_read_case_excel import read_excel_case
from .mil_create_data_excel import create_excel_case
from .mil_update_excel import update_case_excel
from .exceptions import (
MILSDKError,
ExcelReadError,
@@ -23,11 +25,6 @@ from .exceptions import (
)
from .logging_config import setup_logging, get_logger
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
__all__ = [
"DataLog",
"SignalData",
+1 -1
View File
@@ -14,7 +14,7 @@ class DataLog:
time: float = 0.0
value: str = ""
@dataclass
class SignalData:
"""信号数据封装
+19 -19
View File
@@ -11,12 +11,15 @@ import logging
from typing import Any
from .base import DataLog
from .exceptions import ExcelReadError, ExcelFormatError, CaseDataError, ExcelWriteError
from openpyxl import Workbook, load_workbook
from .exceptions import CaseDataError, ExcelWriteError
from openpyxl import Workbook
from openpyxl.worksheet.worksheet import Worksheet
logger = logging.getLogger(__name__)
CaseResultDict = dict[str, Any]
def create_excel_case(
excel_path: str,
data_dict: dict,
@@ -44,7 +47,7 @@ def create_excel_case(
data_dict_copy = {k: v for k, v in data_dict.items()
if k not in ('wb', 'sheet', 'source_row')}
datas_dict = __analysis_case(data_dict_copy, sheets_dict)
datas_dict = _analysis_case(data_dict_copy, sheets_dict)
case_count = 0
for name in datas_dict.keys():
@@ -54,16 +57,14 @@ def create_excel_case(
sheet = new_wb["Scenario1"]
generate_path = f"{excel_path}/{name}.xlsx"
__write_excel_data(sheet, datas_dict[name], source_row)
# new_wb.save(generate_path)
_write_excel_data(sheet, datas_dict[name], source_row)
logger.info(f"已生成用例: {name},路径: {generate_path}")
logger.info(f"测试用例生成完成,共 {case_count} 个用例")
def __write_excel_data(sheet: Worksheet, data_dict: dict, source_row: int) -> None:
def _write_excel_data(sheet: Worksheet, data_dict: dict, source_row: int) -> None:
"""写入 Excel 数据"""
for name in data_dict.keys():
column = data_dict[name]["column"]
@@ -93,8 +94,7 @@ def __write_excel_data(sheet: Worksheet, data_dict: dict, source_row: int) -> No
sheet.cell(source_row + row - 1, column).data_type = "float"
def __analysis_case(data_dict: dict, sheets_dict: dict) -> dict:
def _analysis_case(data_dict: dict, sheets_dict: dict) -> CaseResultDict:
"""分析用例字典,将用例中的信号名替换为信号值
Args:
@@ -104,7 +104,7 @@ def __analysis_case(data_dict: dict, sheets_dict: dict) -> dict:
Returns:
处理后的用例字典
"""
datas_dict = {}
datas_dict: CaseResultDict = {}
for sheet_name in sheets_dict.keys():
sheet_dict = sheets_dict[sheet_name]
@@ -116,12 +116,12 @@ def __analysis_case(data_dict: dict, sheets_dict: dict) -> dict:
continue
datas_dict[case] = copy.deepcopy(data_dict)
__init_data_log(datas_dict[case])
__analysis_step(sheet_dict[case]["step"], datas_dict[case])
_init_data_log(datas_dict[case])
_analysis_step(sheet_dict[case]["step"], datas_dict[case])
return datas_dict
def __analysis_step(step_dict: dict, data_dict: dict) -> None:
def _analysis_step(step_dict: dict, data_dict: dict) -> None:
"""分析步骤字典,将步骤中的信号名替换为信号值
Args:
@@ -130,14 +130,14 @@ def __analysis_step(step_dict: dict, data_dict: dict) -> None:
"""
for step_key in step_dict.keys():
if "action" in step_dict[step_key].keys():
__analysis_data(step_dict[step_key]["action"], data_dict, step_dict[step_key]["time"])
_analysis_data(step_dict[step_key]["action"], data_dict, step_dict[step_key]["time"])
else:
for name in data_dict.keys():
datalog = data_dict[name]["datalog"]
datalog.append(DataLog(step_dict[step_key]["time"], datalog[-1].value))
def __analysis_data(action_dict: dict, data_dict: dict, time: float) -> None:
def _analysis_data(action_dict: dict, data_dict: dict, time: float) -> None:
"""分析数据字典,将数据字典中的信号名替换为信号值
Args:
@@ -148,9 +148,9 @@ def __analysis_data(action_dict: dict, data_dict: dict, time: float) -> None:
Raises:
CaseDataError: 信号不存在
"""
data_log_len = None
data_log_len: int | None = None
for name in action_dict.keys():
matched_key = None
matched_key: str | None = None
for key in data_dict.keys():
if name.lower() == key.strip().lower():
matched_key = key
@@ -171,11 +171,11 @@ def __analysis_data(action_dict: dict, data_dict: dict, time: float) -> None:
datalog.append(DataLog(time, datalog[-1].value))
def __init_data_log(data_dict: dict) -> None:
def _init_data_log(data_dict: dict) -> None:
"""初始化数据日志
Args:
data_dict: 数据字典
"""
for name in data_dict.keys():
data_dict[name]["datalog"] = data_dict[name]["datalog"][:1]
data_dict[name]["datalog"] = data_dict[name]["datalog"][:1]
+33 -28
View File
@@ -13,22 +13,29 @@ Excel 模板格式约定:
- 列 4: 步骤名称
- 列 5: 时间
"""
import copy
import logging
from typing import Any
from .base import DataLog
from .exceptions import ExcelReadError, ExcelFormatError, CaseDataError, ExcelWriteError
from openpyxl import Workbook, load_workbook
from openpyxl import load_workbook
from openpyxl.worksheet.worksheet import Worksheet
from .base import DataLog
from .exceptions import ExcelReadError, ExcelFormatError, CaseDataError
logger = logging.getLogger(__name__)
COL_INDEX_TITLE = 1
COL_INDEX_STATUS = 2
COL_INDEX_ACTION = 3
COL_INDEX_NAME = 4
COL_INDEX_TIME = 5
CaseDict = dict[str, Any]
class CaseColumns:
"""用例 Excel 列索引常量"""
TITLE = 1
STATUS = 2
ACTION = 3
NAME = 4
TIME = 5
STATUS_COMPLETE = "完成测试"
@@ -36,7 +43,7 @@ def read_excel_case(
excel_path: str,
data_dict: dict,
addTimeEn: bool,
) -> dict[str, Any]:
) -> CaseDict:
"""读取 Excel 用例模板
Args:
@@ -63,7 +70,7 @@ def read_excel_case(
raise ExcelReadError(f"无法读取Excel文件 {excel_path}: {str(e)}")
try:
version = __get_template_version(wb["Atech-Hefei"])
version = _get_template_version(wb["Atech-Hefei"])
if version is None:
logger.error("缺少模板版本号")
raise ExcelFormatError("Excel格式错误,缺少模板版本号")
@@ -73,7 +80,7 @@ def read_excel_case(
logger.error(f"缺少 'Atech-Hefei'")
raise ExcelFormatError(f"Excel文件 {excel_path} 格式错误,缺少 Atech-Hefei 表")
result_dict = {}
result_dict: CaseDict = {}
sheet_count = 0
for sheet in wb.worksheets:
sheet_count += 1
@@ -88,11 +95,11 @@ def read_excel_case(
row = 2
old_time = 0.0
while True:
if sheet.cell(row=row, column=COL_INDEX_TITLE).value is not None:
new_head = sheet.cell(row=row, column=COL_INDEX_TITLE).value
if sheet.cell(row=row, column=CaseColumns.TITLE).value is not None:
new_head = sheet.cell(row=row, column=CaseColumns.TITLE).value
if new_head is None:
raise CaseDataError(
f"Excel文件 {excel_path} 格式错误,{sheet.title}{row} 行第 {COL_INDEX_TITLE} 列必须有标题名"
f"Excel文件 {excel_path} 格式错误,{sheet.title}{row} 行第 {CaseColumns.TITLE} 列必须有标题名"
)
if new_head != old_head:
step_id = 0
@@ -102,20 +109,20 @@ def read_excel_case(
result_dict[sheet.title][new_head] = {}
result_dict[sheet.title][new_head]["step"] = {}
if sheet.cell(row=row, column=COL_INDEX_STATUS).value == STATUS_COMPLETE:
if sheet.cell(row=row, column=CaseColumns.STATUS).value == STATUS_COMPLETE:
result_dict[sheet.title][new_head]["enable"] = True
else:
result_dict[sheet.title][new_head]["enable"] = False
step_name = sheet.cell(row, COL_INDEX_NAME).value
step_time = sheet.cell(row, COL_INDEX_TIME).value
step_name = sheet.cell(row, CaseColumns.NAME).value
step_time = sheet.cell(row, CaseColumns.TIME).value
if step_time is None:
break
try:
step_time = float(step_time)
except (ValueError, TypeError):
raise CaseDataError(
f"Excel文件 {excel_path} 格式错误,{sheet.title}{row} 行第 {COL_INDEX_TIME} 列时间必须是数字"
f"Excel文件 {excel_path} 格式错误,{sheet.title}{row} 行第 {CaseColumns.TIME} 列时间必须是数字"
)
result_dict[sheet.title][new_head]["step"][f"step{step_id}"] = {}
@@ -125,10 +132,10 @@ def read_excel_case(
old_time += step_time
result_dict[sheet.title][new_head]["step"][f"step{step_id}"]["time"] = old_time
strings = sheet.cell(row, COL_INDEX_ACTION).value
strings = sheet.cell(row, CaseColumns.ACTION).value
if strings is not None:
result_dict[sheet.title][new_head]["step"][f"step{step_id}"]["action"] = \
__analysis_action(sheet, row, COL_INDEX_ACTION, strings, data_dict, excel_path)
_analysis_action(sheet, row, CaseColumns.ACTION, strings, data_dict, excel_path)
step_id += 1
row += 1
@@ -136,8 +143,7 @@ def read_excel_case(
return result_dict
def __get_template_version(sheet: Worksheet) -> str | None:
def _get_template_version(sheet: Worksheet) -> str | None:
"""获取 Excel 模板版本号
Args:
@@ -148,13 +154,13 @@ def __get_template_version(sheet: Worksheet) -> str | None:
"""
row = 2
version = None
while sheet.cell(row=row, column=COL_INDEX_TITLE).value is not None:
version = sheet.cell(row=row, column=COL_INDEX_TITLE).value
while sheet.cell(row=row, column=CaseColumns.TITLE).value is not None:
version = sheet.cell(row=row, column=CaseColumns.TITLE).value
row += 1
return version
def __analysis_action(
def _analysis_action(
sheet: Worksheet,
row: int,
column: int,
@@ -206,5 +212,4 @@ def __analysis_action(
action_dict[matched_key] = signal_value
return action_dict
return action_dict
+8 -8
View File
@@ -19,6 +19,9 @@ from .exceptions import ExcelReadError, ExcelFormatError
logger = logging.getLogger(__name__)
SignalDict = dict[str, SignalData]
DataDict = dict[str, Any]
@dataclass
class ExcelReaderConfig:
@@ -43,12 +46,11 @@ class ExcelReaderConfig:
block_path_row: int = 4
def read_excel_data(
excel_path: str,
return_object: bool = False,
config: ExcelReaderConfig | None = None
) -> dict[str, Any] | ExcelDataResult:
) -> DataDict | ExcelDataResult:
"""读取 MIL 仿真 Excel 文件并解析信号数据
Args:
@@ -102,7 +104,7 @@ def read_excel_data(
logger.debug(f"找到 {config.source_header} 标记,行号: {source_row}")
signals: dict[str, SignalData] = {}
signals: SignalDict = {}
column = 2
current_header = None
while True:
@@ -119,7 +121,7 @@ def read_excel_data(
if name == "time":
column += 1
continue
if name == "Parameter:" or name == "Value" or name == "BlockPath":
if name in ("Parameter:", "Value", "BlockPath"):
column += 1
continue
sig_type = sheet.cell(config.type_row, column).value
@@ -130,9 +132,6 @@ def read_excel_data(
datalog=get_data_log(sheet, source_row + config.data_start_row_offset, column, config.time_column)
)
logger.debug(f"解析信号: {name}, 数据点: {len(signals[name].datalog)}")
# elif current_header == config.output_header:
# column += 1
# continue
else:
break
column += 1
@@ -147,7 +146,7 @@ def read_excel_data(
signals=signals
)
data: dict[str, Any] = {
data: DataDict = {
"wb": wb,
"sheet": sheet,
"source_row": source_row
@@ -157,6 +156,7 @@ def read_excel_data(
return data
def get_data_log(
sheet: Worksheet,
row: int,
+122
View File
@@ -0,0 +1,122 @@
"""MIL 测试用例 Excel 更新模块
主要功能:
- 比较新旧数据差异
- 添加新信号列或删除旧信号列
"""
import logging
from typing import Any
from .base import SignalData
from .exceptions import CaseDataError
from openpyxl import Workbook
from openpyxl.worksheet.worksheet import Worksheet
logger = logging.getLogger(__name__)
def update_case_excel(filename: str, old_data: dict, new_data: dict) -> None:
"""更新 Excel 文件中的信号列
Args:
filename: Excel 文件路径
old_data: 旧数据字典
new_data: 新数据字典
Raises:
CaseDataError: 数据类型错误
"""
logger.info(f"开始更新 Excel 文件 {filename}")
old_wb = old_data.pop('wb')
old_sheet = old_data.pop('sheet')
source_row = old_data.pop('source_row')
new_data.pop('wb')
new_data.pop('sheet')
new_data.pop('source_row')
if not isinstance(old_wb, Workbook) or not isinstance(old_sheet, Worksheet):
logger.error("数据类型错误,Workbook 或 Worksheet 类型不匹配")
raise CaseDataError("数据异常,Workbook 或 Worksheet 类型错误")
add_input = _get_add_input(old_data, new_data)
del_input = _get_del_input(old_data, new_data)
datalog_len = _get_datalog_len(old_data)
for name, info in reversed(del_input.items()):
old_sheet.delete_cols(info['column'])
logger.info(f"删除第{info['column']}\t信号名: {name}")
for name, info in add_input.items():
old_sheet.insert_cols(info['column'])
old_sheet.cell(1, info['column']).value = name
old_sheet.cell(1, info['column']).data_type = "str"
old_sheet.cell(3, info['column']).value = info['type']
old_sheet.cell(3, info['column']).data_type = "str"
for index in range(source_row + 1, datalog_len + source_row + 1):
try:
value = int(info['datalog'][0].value)
old_sheet.cell(index, info['column']).value = value
old_sheet.cell(index, info['column']).data_type = "int"
except (ValueError, TypeError):
value = str(info['datalog'][0].value)
old_sheet.cell(index, info['column']).value = value
old_sheet.cell(index, info['column']).data_type = "str"
logger.info(f"新增第{info['column']}\t信号名: {name}")
old_wb.save(filename)
logger.info(f"更新 Excel 文件 {filename} 完成")
def _get_add_input(old_data: dict, new_data: dict) -> dict[str, SignalData]:
"""获取新增输入数据
Args:
old_data: 旧数据字典
new_data: 新数据字典
Returns:
新增信号字典
"""
add_input: dict[str, SignalData] = {}
for name in new_data.keys():
if name not in old_data.keys():
add_input[name] = new_data[name]
return add_input
def _get_del_input(old_data: dict, new_data: dict) -> dict[str, SignalData]:
"""获取删除输入数据
Args:
old_data: 旧数据字典
new_data: 新数据字典
Returns:
删除信号字典
"""
del_input: dict[str, SignalData] = {}
for name in old_data.keys():
if name not in new_data.keys():
del_input[name] = old_data[name]
return del_input
def _get_datalog_len(old_data: dict) -> int:
"""获取数据日志长度
Args:
old_data: 数据字典
Returns:
数据日志长度
"""
for name in old_data.keys():
return len(old_data[name]['datalog'])
return 0