""" 测试报告生成脚本 生成完整的测试报告,包括: - 测试执行摘要 - 覆盖率报告 - 性能测试结果 - 安全测试结果 - Bug清单 """ import os import json import subprocess from datetime import datetime from pathlib import Path class TestReportGenerator: """测试报告生成器""" def __init__(self, project_root: str): self.project_root = Path(project_root) self.report_dir = self.project_root / "test_reports" self.report_dir.mkdir(exist_ok=True) self.timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") self.report_data = { "timestamp": datetime.now().isoformat(), "project": "资产管理系统", "version": "1.0.0", "summary": {}, "unit_tests": {}, "integration_tests": {}, "e2e_tests": {}, "coverage": {}, "performance": {}, "security": {}, "bugs": [] } def run_unit_tests(self): """运行单元测试""" print("=" * 60) print("运行单元测试...") print("=" * 60) cmd = [ "pytest", "-v", "-m", "unit", "--html=test_reports/unit_test_report.html", "--self-contained-html", "--json-report", "--json-report-file=test_reports/unit_test_results.json" ] result = subprocess.run(cmd, capture_output=True, text=True) # 解析结果 if os.path.exists("test_reports/unit_test_results.json"): with open("test_reports/unit_test_results.json", "r") as f: data = json.load(f) self.report_data["unit_tests"] = { "total": data.get("summary", {}).get("total", 0), "passed": data.get("summary", {}).get("passed", 0), "failed": data.get("summary", {}).get("failed", 0), "skipped": data.get("summary", {}).get("skipped", 0), "duration": data.get("summary", {}).get("duration", 0) } return result.returncode == 0 def run_integration_tests(self): """运行集成测试""" print("\n" + "=" * 60) print("运行集成测试...") print("=" * 60) cmd = [ "pytest", "-v", "-m", "integration", "--html=test_reports/integration_test_report.html", "--self-contained-html" ] result = subprocess.run(cmd, capture_output=True, text=True) return result.returncode == 0 def run_coverage_tests(self): """运行覆盖率测试""" print("\n" + "=" * 60) print("生成覆盖率报告...") print("=" * 60) cmd = [ "pytest", "--cov=app", "--cov-report=html:test_reports/htmlcov", "--cov-report=term-missing", "--cov-report=json:test_reports/coverage.json", "--cov-fail-under=70" ] result = subprocess.run(cmd, capture_output=True, text=True) # 解析覆盖率数据 if os.path.exists("test_reports/coverage.json"): with open("test_reports/coverage.json", "r") as f: data = json.load(f) totals = data.get("totals", {}) self.report_data["coverage"] = { "line_coverage": totals.get("percent_covered", 0), "lines_covered": totals.get("covered_lines", 0), "lines_missing": totals.get("missing_lines", 0), "num_statements": totals.get("num_statements", 0) } return result.returncode == 0 def run_security_tests(self): """运行安全测试""" print("\n" + "=" * 60) print("运行安全测试...") print("=" * 60) cmd = [ "pytest", "-v", "tests/security/", "-m", "security", "--html=test_reports/security_test_report.html" ] result = subprocess.run(cmd, capture_output=True, text=True) return result.returncode == 0 def collect_bugs(self): """收集测试中发现的Bug""" print("\n" + "=" * 60) print("分析测试结果,收集Bug...") print("=" * 60) bugs = [] # 从失败的测试中提取Bug test_results = [ "test_reports/unit_test_results.json", "test_reports/integration_test_results.json" ] for result_file in test_results: if os.path.exists(result_file): with open(result_file, "r") as f: data = json.load(f) for test in data.get("tests", []): if test.get("outcome") == "failed": bugs.append({ "test_name": test.get("name"), "error": test.get("call", {}).get("crash", {}).get("message", ""), "severity": "high" if "critical" in test.get("name", "").lower() else "medium", "status": "open" }) self.report_data["bugs"] = bugs return bugs def generate_html_report(self): """生成HTML测试报告""" print("\n" + "=" * 60) print("生成HTML测试报告...") print("=" * 60) html_template = """
| 测试类型 | 总数 | 通过 | 失败 | 通过率 |
|---|---|---|---|---|
| 单元测试 | {unit_total} | {unit_passed} | {unit_failed} | {unit_pass_rate}% |
| 集成测试 | {integration_total} | {integration_passed} | {integration_failed} | {integration_pass_rate}% |
| E2E测试 | {e2e_total} | {e2e_passed} | {e2e_failed} | {e2e_pass_rate}% |