Files
gym-manage/test-suite/generate_test_report.py
T

229 lines
8.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""
测试套件执行报告生成器
用途:
- 统计测试用例数量
- 分析测试覆盖率
- 生成测试执行摘要
- 输出测试报告
"""
import os
import sys
import json
import subprocess
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Any
class TestReportGenerator:
"""测试报告生成器"""
def __init__(self, test_suite_path: str):
self.test_suite_path = Path(test_suite_path)
self.tests_path = self.test_suite_path / "tests"
self.report_data = {
"generated_at": datetime.now().isoformat(),
"test_suites": {},
"summary": {
"total_test_files": 0,
"total_test_cases": 0,
"test_categories": {}
}
}
def count_test_cases(self, file_path: Path) -> int:
"""统计测试文件中的测试用例数量"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# 统计以async def test_或def test_开头的函数
count = content.count('async def test_') + content.count('def test_')
return count
except Exception as e:
print(f"Error reading {file_path}: {e}")
return 0
def analyze_test_directory(self, dir_path: Path, category: str) -> Dict[str, Any]:
"""分析测试目录"""
test_files = list(dir_path.glob("test_*.py"))
category_data = {
"test_files": [],
"total_files": len(test_files),
"total_cases": 0
}
for test_file in test_files:
case_count = self.count_test_cases(test_file)
file_info = {
"file_name": test_file.name,
"relative_path": str(test_file.relative_to(self.tests_path)),
"test_cases": case_count
}
category_data["test_files"].append(file_info)
category_data["total_cases"] += case_count
return category_data
def generate_report(self) -> Dict[str, Any]:
"""生成测试报告"""
print("正在分析测试套件...")
# 分析各个测试目录
test_categories = {
"unit": self.tests_path / "unit",
"integration": self.tests_path / "integration",
"e2e": self.tests_path / "e2e",
"uat": self.tests_path / "uat",
"performance": self.tests_path / "performance",
"security": self.tests_path / "security"
}
for category, path in test_categories.items():
if path.exists():
print(f"分析 {category} 测试...")
category_data = self.analyze_test_directory(path, category)
self.report_data["test_suites"][category] = category_data
# 更新汇总信息
self.report_data["summary"]["total_test_files"] += category_data["total_files"]
self.report_data["summary"]["total_test_cases"] += category_data["total_cases"]
self.report_data["summary"]["test_categories"][category] = {
"files": category_data["total_files"],
"cases": category_data["total_cases"]
}
return self.report_data
def print_report(self):
"""打印测试报告"""
print("\n" + "="*60)
print(" Novalon后台管理系统 - 测试套件执行报告")
print("="*60)
print(f"\n生成时间: {self.report_data['generated_at']}")
print("\n" + "-"*60)
print(" 测试套件统计")
print("-"*60)
for category, data in self.report_data["test_suites"].items():
print(f"\n{category.upper()} 测试:")
print(f" 测试文件数: {data['total_files']}")
print(f" 测试用例数: {data['total_cases']}")
if data['test_files']:
print(f" 测试文件列表:")
for file_info in data['test_files']:
print(f" - {file_info['file_name']}: {file_info['test_cases']} 个用例")
print("\n" + "-"*60)
print(" 汇总信息")
print("-"*60)
print(f"\n总测试文件数: {self.report_data['summary']['total_test_files']}")
print(f"总测试用例数: {self.report_data['summary']['total_test_cases']}")
print("\n测试分类统计:")
for category, stats in self.report_data["summary"]["test_categories"].items():
print(f" {category}: {stats['files']} 文件, {stats['cases']} 用例")
print("\n" + "="*60)
def save_report(self, output_file: str):
"""保存测试报告到文件"""
output_path = self.test_suite_path / output_file
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(self.report_data, f, indent=2, ensure_ascii=False)
print(f"\n测试报告已保存到: {output_path}")
def generate_markdown_report(self, output_file: str):
"""生成Markdown格式的测试报告"""
output_path = self.test_suite_path / output_file
with open(output_path, 'w', encoding='utf-8') as f:
f.write("# Novalon后台管理系统 - 测试套件执行报告\n\n")
f.write(f"**生成时间**: {self.report_data['generated_at']}\n\n")
f.write("## 测试套件统计\n\n")
for category, data in self.report_data["test_suites"].items():
f.write(f"### {category.upper()} 测试\n\n")
f.write(f"- **测试文件数**: {data['total_files']}\n")
f.write(f"- **测试用例数**: {data['total_cases']}\n\n")
if data['test_files']:
f.write("**测试文件列表**:\n\n")
for file_info in data['test_files']:
f.write(f"- `{file_info['file_name']}`: {file_info['test_cases']} 个用例\n")
f.write("\n")
f.write("## 汇总信息\n\n")
f.write(f"- **总测试文件数**: {self.report_data['summary']['total_test_files']}\n")
f.write(f"- **总测试用例数**: {self.report_data['summary']['total_test_cases']}\n\n")
f.write("### 测试分类统计\n\n")
f.write("| 测试类型 | 文件数 | 用例数 |\n")
f.write("|---------|--------|--------|\n")
for category, stats in self.report_data["summary"]["test_categories"].items():
f.write(f"| {category} | {stats['files']} | {stats['cases']} |\n")
f.write("\n## 测试执行建议\n\n")
f.write("### 快速测试\n")
f.write("```bash\n")
f.write("./run_tests.sh integration -v\n")
f.write("```\n\n")
f.write("### 完整测试\n")
f.write("```bash\n")
f.write("./run_tests.sh all -v\n")
f.write("```\n\n")
f.write("### UAT验收测试\n")
f.write("```bash\n")
f.write("./run_uat_tests.sh all -v\n")
f.write("```\n\n")
f.write("## 测试报告查看\n\n")
f.write("### 查看覆盖率报告\n")
f.write("```bash\n")
f.write("open htmlcov/all/index.html\n")
f.write("```\n\n")
f.write("### 查看Allure报告\n")
f.write("```bash\n")
f.write("allure serve allure-results/all\n")
f.write("```\n")
print(f"Markdown报告已保存到: {output_path}")
def main():
"""主函数"""
# 获取测试套件路径
script_path = Path(__file__).parent
test_suite_path = script_path
# 创建报告生成器
generator = TestReportGenerator(str(test_suite_path))
# 生成报告
generator.generate_report()
# 打印报告
generator.print_report()
# 保存JSON报告
generator.save_report("test_suite_report.json")
# 生成Markdown报告
generator.generate_markdown_report("TEST_SUITE_REPORT.md")
print("\n✅ 测试套件报告生成完成!")
if __name__ == "__main__":
main()