""" 测试报告生成器模块 提供测试报告生成功能,支持多种报告格式。 """ import json import os from pathlib import Path from typing import Dict, List, Any, Optional from datetime import datetime from dataclasses import dataclass, field, asdict @dataclass class TestResult: """测试结果数据类""" name: str status: str # passed, failed, skipped duration: float = 0.0 start_time: Optional[str] = None end_time: Optional[str] = None error_message: Optional[str] = None traceback: Optional[str] = None screenshot: Optional[str] = None steps: List[Dict[str, Any]] = field(default_factory=list) @dataclass class TestSuite: """测试套件数据类""" name: str tests: List[TestResult] = field(default_factory=list) @property def passed_count(self) -> int: return sum(1 for t in self.tests if t.status == "passed") @property def failed_count(self) -> int: return sum(1 for t in self.tests if t.status == "failed") @property def skipped_count(self) -> int: return sum(1 for t in self.tests if t.status == "skipped") @property def total_count(self) -> int: return len(self.tests) @property def pass_rate(self) -> float: if self.total_count == 0: return 0.0 return (self.passed_count / self.total_count) * 100 class TestReporter: """测试报告生成器""" def __init__(self, report_dir: str = "reports"): self.report_dir = Path(report_dir) self.report_dir.mkdir(parents=True, exist_ok=True) self.suites: Dict[str, TestSuite] = {} self.start_time: Optional[datetime] = None self.end_time: Optional[datetime] = None def start_report(self) -> None: """开始测试报告""" self.start_time = datetime.now() print(f"📝 测试报告开始于: {self.start_time.strftime('%Y-%m-%d %H:%M:%S')}") def end_report(self) -> None: """结束测试报告""" self.end_time = datetime.now() print(f"📝 测试报告结束于: {self.end_time.strftime('%Y-%m-%d %H:%M:%S')}") def add_test_result(self, suite_name: str, result: TestResult) -> None: """添加测试结果""" if suite_name not in self.suites: self.suites[suite_name] = TestSuite(name=suite_name) self.suites[suite_name].tests.append(result) def generate_html_report(self, filename: str = "test_report.html") -> str: """生成HTML报告""" filepath = self.report_dir / filename total_tests = sum(s.total_count for s in self.suites.values()) total_passed = sum(s.passed_count for s in self.suites.values()) total_failed = sum(s.failed_count for s in self.suites.values()) total_skipped = sum(s.skipped_count for s in self.suites.values()) html_content = f""" E2E测试报告

🧪 E2E测试报告

生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

总测试数

{total_tests}

通过

{total_passed}

失败

{total_failed}

跳过

{total_skipped}
""" # 添加测试套件详情 for suite_name, suite in self.suites.items(): html_content += f"""

{suite_name}

通过率: {suite.pass_rate:.1f}% ({suite.passed_count}/{suite.total_count})

""" for test in suite.tests: status_class = test.status error_html = "" if test.error_message: error_html = f'
{test.error_message}
' html_content += f"""
{test.name} {test.duration:.2f}s {error_html}
{test.status.upper()}
""" html_content += """
""" html_content += """
""" with open(filepath, "w", encoding="utf-8") as f: f.write(html_content) print(f"📊 HTML报告已生成: {filepath}") return str(filepath) def generate_json_report(self, filename: str = "test_report.json") -> str: """生成JSON报告""" filepath = self.report_dir / filename report_data = { "report_info": { "generated_at": datetime.now().isoformat(), "start_time": self.start_time.isoformat() if self.start_time else None, "end_time": self.end_time.isoformat() if self.end_time else None, }, "summary": { "total": sum(s.total_count for s in self.suites.values()), "passed": sum(s.passed_count for s in self.suites.values()), "failed": sum(s.failed_count for s in self.suites.values()), "skipped": sum(s.skipped_count for s in self.suites.values()), }, "suites": {} } for suite_name, suite in self.suites.items(): report_data["suites"][suite_name] = { "summary": { "total": suite.total_count, "passed": suite.passed_count, "failed": suite.failed_count, "skipped": suite.skipped_count, "pass_rate": suite.pass_rate, }, "tests": [asdict(test) for test in suite.tests] } with open(filepath, "w", encoding="utf-8") as f: json.dump(report_data, f, ensure_ascii=False, indent=2) print(f"📊 JSON报告已生成: {filepath}") return str(filepath) def generate_all_reports(self) -> Dict[str, str]: """生成所有报告""" return { "html": self.generate_html_report(), "json": self.generate_json_report(), }