Files
test_item_gen/modules/output_formatter.py
2026-02-04 14:38:52 +08:00

333 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# @line_count 300
"""多格式输出模块"""
import json
from pathlib import Path
from typing import List, Dict, Any, Optional
from datetime import datetime
try:
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
OPENPYXL_AVAILABLE = True
except ImportError:
OPENPYXL_AVAILABLE = False
class OutputFormatter:
"""多格式输出格式化器"""
def __init__(self, test_items: List[Dict[str, Any]], test_cases: List[Dict[str, Any]],
document_info: Optional[Dict[str, Any]] = None):
"""
初始化输出格式化器
Args:
test_items: 测试项列表
test_cases: 测试用例列表
document_info: 文档信息
"""
self.test_items = test_items
self.test_cases = test_cases
self.document_info = document_info or {}
def to_json(self, output_path: Optional[str] = None) -> str:
"""
输出为JSON格式
Args:
output_path: 输出文件路径如果为None则返回JSON字符串
Returns:
JSON字符串或文件路径
"""
data = {
'document_info': self.document_info,
'generation_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'summary': {
'test_item_count': len(self.test_items),
'test_case_count': len(self.test_cases)
},
'test_items': self.test_items,
'test_cases': self.test_cases
}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
if output_path:
output_path = Path(output_path)
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(json_str)
return str(output_path)
return json_str
def to_markdown(self, output_path: Optional[str] = None) -> str:
"""
输出为Markdown格式
Args:
output_path: 输出文件路径如果为None则返回Markdown字符串
Returns:
Markdown字符串或文件路径
"""
lines = []
# 标题和文档信息
lines.append("# 测试项和测试用例文档\n")
if self.document_info.get('title'):
lines.append(f"**文档标题**: {self.document_info['title']}\n")
if self.document_info.get('version'):
lines.append(f"**版本**: {self.document_info['version']}\n")
lines.append(f"**生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
lines.append(f"**测试项数量**: {len(self.test_items)}\n")
lines.append(f"**测试用例数量**: {len(self.test_cases)}\n")
lines.append("\n---\n")
# 按模块分组
modules = {}
for item in self.test_items:
module_name = item.get('module_name', '未分类')
if module_name not in modules:
modules[module_name] = []
modules[module_name].append(item)
# 输出每个模块的测试项和测试用例
for module_name, items in modules.items():
lines.append(f"\n## {module_name}\n")
for item in items:
# 测试项
lines.append(f"\n### {item.get('id', '')} {item.get('name', '')}\n")
lines.append(f"- **测试类型**: {item.get('test_type', 'N/A')}")
lines.append(f"- **优先级**: {item.get('priority', 'N/A')}")
lines.append(f"- **测试目标**: {item.get('test_objective', 'N/A')}\n")
# 该测试项下的测试用例
item_cases = [case for case in self.test_cases
if case.get('test_item_id') == item.get('id')]
if item_cases:
lines.append("#### 测试用例\n")
for case in item_cases:
lines.append(f"\n**{case.get('id', '')} {case.get('name', '')}**\n")
lines.append(f"- **前置条件**: {case.get('preconditions', 'N/A')}")
lines.append(f"- **优先级**: {case.get('priority', 'N/A')}")
lines.append(f"- **测试类型**: {case.get('test_type', 'N/A')}\n")
lines.append("**测试步骤**:\n")
for idx, step in enumerate(case.get('test_steps', []), 1):
lines.append(f"{idx}. {step}\n")
lines.append(f"\n**预期结果**: {case.get('expected_result', 'N/A')}\n")
lines.append("---\n")
markdown_str = '\n'.join(lines)
if output_path:
output_path = Path(output_path)
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(markdown_str)
return str(output_path)
return markdown_str
def to_excel(self, output_path: str) -> str:
"""
输出为Excel格式
Args:
output_path: 输出文件路径
Returns:
文件路径
"""
if not OPENPYXL_AVAILABLE:
raise ImportError("openpyxl未安装无法生成Excel文件。请运行: pip install openpyxl")
wb = Workbook()
# 删除默认工作表
if 'Sheet' in wb.sheetnames:
wb.remove(wb['Sheet'])
# 创建测试项工作表
self._create_test_items_sheet(wb)
# 创建测试用例工作表
self._create_test_cases_sheet(wb)
# 创建摘要工作表
self._create_summary_sheet(wb)
# 保存文件
output_path = Path(output_path)
output_path.parent.mkdir(parents=True, exist_ok=True)
wb.save(output_path)
return str(output_path)
def _create_test_items_sheet(self, wb: Workbook):
"""创建测试项工作表"""
ws = wb.create_sheet("测试项", 0)
# 表头
headers = ['测试项ID', '测试项名称', '所属模块', '功能名称', '测试类型', '优先级', '测试目标']
ws.append(headers)
# 设置表头样式
header_fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid")
header_font = Font(bold=True, color="FFFFFF")
border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
for col in range(1, len(headers) + 1):
cell = ws.cell(1, col)
cell.fill = header_fill
cell.font = header_font
cell.border = border
cell.alignment = Alignment(horizontal='center', vertical='center')
# 数据行
for item in self.test_items:
row = [
item.get('id', ''),
item.get('name', ''),
item.get('module_name', ''),
item.get('function_name', ''),
item.get('test_type', ''),
item.get('priority', ''),
item.get('test_objective', '')
]
ws.append(row)
# 设置边框
for col in range(1, len(headers) + 1):
ws.cell(ws.max_row, col).border = border
# 调整列宽
column_widths = [12, 30, 15, 15, 12, 8, 40]
for col, width in enumerate(column_widths, 1):
ws.column_dimensions[ws.cell(1, col).column_letter].width = width
# 冻结首行
ws.freeze_panes = 'A2'
def _create_test_cases_sheet(self, wb: Workbook):
"""创建测试用例工作表"""
ws = wb.create_sheet("测试用例", 1)
# 表头
headers = ['测试用例ID', '测试项ID', '测试用例名称', '所属模块', '前置条件',
'测试步骤', '预期结果', '优先级', '测试类型']
ws.append(headers)
# 设置表头样式
header_fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid")
header_font = Font(bold=True, color="FFFFFF")
border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
for col in range(1, len(headers) + 1):
cell = ws.cell(1, col)
cell.fill = header_fill
cell.font = header_font
cell.border = border
cell.alignment = Alignment(horizontal='center', vertical='center')
# 数据行
for case in self.test_cases:
test_steps_str = '\n'.join([f"{idx}. {step}" for idx, step
in enumerate(case.get('test_steps', []), 1)])
row = [
case.get('id', ''),
case.get('test_item_id', ''),
case.get('name', ''),
case.get('module_name', ''),
case.get('preconditions', ''),
test_steps_str,
case.get('expected_result', ''),
case.get('priority', ''),
case.get('test_type', '')
]
ws.append(row)
# 设置边框和换行
for col in range(1, len(headers) + 1):
cell = ws.cell(ws.max_row, col)
cell.border = border
if col == 6: # 测试步骤列
cell.alignment = Alignment(wrap_text=True, vertical='top')
else:
cell.alignment = Alignment(vertical='top')
# 调整列宽
column_widths = [12, 12, 30, 15, 25, 40, 30, 8, 12]
for col, width in enumerate(column_widths, 1):
ws.column_dimensions[ws.cell(1, col).column_letter].width = width
# 设置行高(为测试步骤列预留空间)
for row in range(2, ws.max_row + 1):
ws.row_dimensions[row].height = 60
# 冻结首行
ws.freeze_panes = 'A2'
def _create_summary_sheet(self, wb: Workbook):
"""创建摘要工作表"""
ws = wb.create_sheet("摘要", 2)
# 文档信息
if self.document_info.get('title'):
ws.append(['文档标题', self.document_info['title']])
if self.document_info.get('version'):
ws.append(['版本', self.document_info['version']])
ws.append(['生成时间', datetime.now().strftime('%Y-%m-%d %H:%M:%S')])
ws.append([])
# 统计信息
ws.append(['统计项', '数量'])
ws.append(['测试项总数', len(self.test_items)])
ws.append(['测试用例总数', len(self.test_cases)])
ws.append([])
# 按模块统计
ws.append(['模块', '测试项数量', '测试用例数量'])
modules = {}
for item in self.test_items:
module_name = item.get('module_name', '未分类')
if module_name not in modules:
modules[module_name] = {'items': 0, 'cases': 0}
modules[module_name]['items'] += 1
for case in self.test_cases:
module_name = case.get('module_name', '未分类')
if module_name not in modules:
modules[module_name] = {'items': 0, 'cases': 0}
modules[module_name]['cases'] += 1
for module_name, stats in modules.items():
ws.append([module_name, stats['items'], stats['cases']])
# 设置样式
header_font = Font(bold=True)
for row in ws.iter_rows(min_row=1, max_row=1):
for cell in row:
cell.font = header_font
# 调整列宽
ws.column_dimensions['A'].width = 20
ws.column_dimensions['B'].width = 15
ws.column_dimensions['C'].width = 15