#!/usr/bin/env python3 """ 测试报告生成脚本 生成详细的HTML测试报告,包含测试结果、截图、缺陷统计等 """ import json import os from pathlib import Path from datetime import datetime from typing import List, Dict, Optional from dataclasses import dataclass, asdict import base64 @dataclass class TestCase: """测试用例""" id: str name: str description: str status: str # passed, failed, skipped duration: float error_message: Optional[str] = None screenshot_path: Optional[str] = None steps: List[str] = None timestamp: str = None def __post_init__(self): if self.steps is None: self.steps = [] self.timestamp = datetime.now().isoformat() @dataclass class TestSuite: """测试套件""" name: str test_cases: List[TestCase] start_time: str end_time: str total_duration: float @property def total_tests(self) -> int: return len(self.test_cases) @property def passed_tests(self) -> int: return len([tc for tc in self.test_cases if tc.status == "passed"]) @property def failed_tests(self) -> int: return len([tc for tc in self.test_cases if tc.status == "failed"]) @property def skipped_tests(self) -> int: return len([tc for tc in self.test_cases if tc.status == "skipped"]) @property def pass_rate(self) -> float: if self.total_tests == 0: return 0.0 return (self.passed_tests / self.total_tests) * 100 class TestReportGenerator: """测试报告生成器""" def __init__(self, output_dir: str = "test_reports"): self.output_dir = Path(output_dir) self.output_dir.mkdir(exist_ok=True) self.test_suites: List[TestSuite] = [] def add_test_suite(self, test_suite: TestSuite): """添加测试套件""" self.test_suites.append(test_suite) def generate_html_report(self) -> str: """生成HTML报告""" html_content = self._generate_html() timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") report_file = self.output_dir / f"test_report_{timestamp}.html" with open(report_file, 'w', encoding='utf-8') as f: f.write(html_content) return str(report_file) def generate_json_report(self) -> str: """生成JSON报告""" report_data = { "generated_at": datetime.now().isoformat(), "test_suites": [asdict(suite) for suite in self.test_suites], "summary": self._generate_summary() } timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") report_file = self.output_dir / f"test_report_{timestamp}.json" with open(report_file, 'w', encoding='utf-8') as f: json.dump(report_data, f, indent=2, ensure_ascii=False) return str(report_file) def _generate_summary(self) -> Dict: """生成测试摘要""" total_tests = sum(suite.total_tests for suite in self.test_suites) total_passed = sum(suite.passed_tests for suite in self.test_suites) total_failed = sum(suite.failed_tests for suite in self.test_suites) total_skipped = sum(suite.skipped_tests for suite in self.test_suites) total_duration = sum(suite.total_duration for suite in self.test_suites) overall_pass_rate = (total_passed / total_tests * 100) if total_tests > 0 else 0 # 统计缺陷 defects = [] for suite in self.test_suites: for test_case in suite.test_cases: if test_case.status == "failed" and test_case.error_message: defects.append({ "test_case": test_case.name, "test_suite": suite.name, "error": test_case.error_message, "timestamp": test_case.timestamp }) return { "total_tests": total_tests, "total_passed": total_passed, "total_failed": total_failed, "total_skipped": total_skipped, "overall_pass_rate": overall_pass_rate, "total_duration": total_duration, "defects": defects, "test_suites_count": len(self.test_suites) } def _generate_html(self) -> str: """生成HTML内容""" summary = self._generate_summary() html = f"""
生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
总测试数
通过测试
失败测试
通过率
{test_case.description}
{test_case.error_message}
截图加载失败: {str(e)}
测试套件: {defect['test_suite']}
错误: {defect['error']}
时间: {defect['timestamp']}