08ea5fbe98
添加用户管理视图、API和状态管理文件
247 lines
8.6 KiB
Python
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())
|