Files
everything-is-suitable/everything-is-suitable-test/python_e2e/run_full_test_suite.py
T
张翔 08ea5fbe98 feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
2026-03-28 14:37:29 +08:00

247 lines
8.6 KiB
Python

#!/usr/bin/env python3
"""
完整测试套件执行脚本
执行所有测试并生成详细报告。
"""
import subprocess
import sys
import json
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Any
class TestSuiteRunner:
"""测试套件运行器"""
def __init__(self):
self.results: Dict[str, Any] = {}
self.start_time = None
self.end_time = None
def run_test_module(self, module: str, description: str) -> Dict[str, Any]:
"""运行测试模块"""
print(f"\n{'='*60}")
print(f"🧪 {description}")
print(f"{'='*60}")
cmd = [
"python", "-m", "pytest", module,
"-v", "--tb=short", "-q", "--no-header",
"--json-report", "--json-report-file=reports/temp_report.json"
]
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=300
)
# 解析结果
passed = result.returncode == 0
output = result.stdout + result.stderr
# 统计测试数量
lines = output.split('\n')
test_count = 0
for line in lines:
if 'passed' in line or 'failed' in line or 'skipped' in line:
# 解析测试统计
parts = line.split()
for part in parts:
if 'passed' in part:
test_count += int(part.split()[0]) if part[0].isdigit() else 0
elif 'failed' in part:
test_count += int(part.split()[0]) if part[0].isdigit() else 0
print(f"✅ 测试完成: {test_count} 个测试")
return {
"module": module,
"description": description,
"passed": passed,
"output": output,
"test_count": test_count,
"timestamp": datetime.now().isoformat()
}
except subprocess.TimeoutExpired:
print(f"❌ 测试超时: {module}")
return {
"module": module,
"description": description,
"passed": False,
"error": "Timeout",
"timestamp": datetime.now().isoformat()
}
except Exception as e:
print(f"❌ 测试失败: {str(e)}")
return {
"module": module,
"description": description,
"passed": False,
"error": str(e),
"timestamp": datetime.now().isoformat()
}
def run_all_tests(self) -> Dict[str, Any]:
"""运行所有测试"""
self.start_time = datetime.now()
print("🚀 开始执行完整测试套件")
print(f"开始时间: {self.start_time.strftime('%Y-%m-%d %H:%M:%S')}")
# 创建报告目录
Path("reports").mkdir(exist_ok=True)
# 定义测试模块
test_modules = [
("tests/web/test_auth.py", "认证模块测试"),
("tests/web/test_user_management.py", "用户管理测试"),
("tests/web/test_role_management.py", "角色管理测试"),
("tests/web/test_role_management_green.py", "角色管理Green测试"),
("tests/web/test_boundary_conditions.py", "边界条件测试"),
("tests/web/test_performance.py", "性能测试"),
("tests/web/test_integration.py", "集成测试"),
("tests/uniapp/test_almanac.py", "黄历模块测试"),
("tests/uniapp/test_calendar.py", "日历模块测试"),
]
# 运行所有测试模块
for module, description in test_modules:
result = self.run_test_module(module, description)
self.results[module] = result
self.end_time = datetime.now()
return self.generate_report()
def generate_report(self) -> Dict[str, Any]:
"""生成测试报告"""
total_tests = sum(r.get("test_count", 0) for r in self.results.values())
passed_tests = sum(1 for r in self.results.values() if r.get("passed", False))
failed_tests = len(self.results) - passed_tests
duration = (self.end_time - self.start_time).total_seconds()
report = {
"summary": {
"total_modules": len(self.results),
"passed_modules": passed_tests,
"failed_modules": failed_tests,
"total_test_cases": total_tests,
"duration_seconds": duration,
"start_time": self.start_time.isoformat(),
"end_time": self.end_time.isoformat(),
},
"modules": self.results,
"timestamp": datetime.now().isoformat()
}
# 保存报告
report_file = Path("reports/full_test_report.json")
with open(report_file, "w", encoding="utf-8") as f:
json.dump(report, f, indent=2, ensure_ascii=False)
# 生成HTML报告
self._generate_html_report(report)
return report
def _generate_html_report(self, report: Dict[str, Any]):
"""生成HTML报告"""
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>完整测试套件报告</title>
<style>
body {{ font-family: Arial, sans-serif; margin: 20px; }}
h1 {{ color: #333; }}
.summary {{ background: #f0f0f0; padding: 15px; border-radius: 5px; margin: 20px 0; }}
.module {{ margin: 10px 0; padding: 10px; border-left: 4px solid #ccc; }}
.passed {{ border-left-color: #4CAF50; background: #e8f5e9; }}
.failed {{ border-left-color: #f44336; background: #ffebee; }}
.timestamp {{ color: #666; font-size: 0.9em; }}
pre {{ background: #f5f5f5; padding: 10px; overflow-x: auto; }}
</style>
</head>
<body>
<h1>🧪 完整测试套件报告</h1>
<div class="summary">
<h2>测试摘要</h2>
<p><strong>总模块数:</strong> {report['summary']['total_modules']}</p>
<p><strong>通过模块:</strong> {report['summary']['passed_modules']}</p>
<p><strong>失败模块:</strong> {report['summary']['failed_modules']}</p>
<p><strong>总测试用例:</strong> {report['summary']['total_test_cases']}</p>
<p><strong>执行时间:</strong> {report['summary']['duration_seconds']:.2f} 秒</p>
<p><strong>开始时间:</strong> {report['summary']['start_time']}</p>
<p><strong>结束时间:</strong> {report['summary']['end_time']}</p>
</div>
<h2>详细结果</h2>
"""
for module, result in report['modules'].items():
status_class = "passed" if result.get("passed", False) else "failed"
status_icon = "" if result.get("passed", False) else ""
html_content += f"""
<div class="module {status_class}">
<h3>{status_icon} {result['description']}</h3>
<p><strong>模块:</strong> {module}</p>
<p><strong>状态:</strong> {"通过" if result.get("passed", False) else "失败"}</p>
<p><strong>测试数:</strong> {result.get('test_count', 0)}</p>
<p class="timestamp">{result.get('timestamp', '')}</p>
</div>
"""
html_content += """
</body>
</html>
"""
html_file = Path("reports/full_test_report.html")
with open(html_file, "w", encoding="utf-8") as f:
f.write(html_content)
def print_summary(self, report: Dict[str, Any]):
"""打印测试摘要"""
print("\n" + "="*60)
print("📊 测试执行摘要")
print("="*60)
summary = report['summary']
print(f"总模块数: {summary['total_modules']}")
print(f"通过模块: {summary['passed_modules']}")
print(f"失败模块: {summary['failed_modules']}")
print(f"总测试用例: {summary['total_test_cases']}")
print(f"执行时间: {summary['duration_seconds']:.2f}")
print("\n模块详情:")
for module, result in report['modules'].items():
status = "✅ 通过" if result.get("passed", False) else "❌ 失败"
print(f" {status} - {result['description']}")
print(f"\n📄 报告已保存:")
print(f" - JSON: reports/full_test_report.json")
print(f" - HTML: reports/full_test_report.html")
def main():
"""主函数"""
runner = TestSuiteRunner()
report = runner.run_all_tests()
runner.print_summary(report)
# 返回退出码
failed = report['summary']['failed_modules']
return 0 if failed == 0 else 1
if __name__ == "__main__":
sys.exit(main())