You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

325 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env python3
"""
测试运行器 - 统一管理所有测试
包含问题检测、修复建议和测试报告
"""
import os
import sys
import subprocess
import json
import requests
import time
from pathlib import Path
# 项目路径配置
PROJECT_ROOT = Path(__file__).parent.parent
DJANGO_ROOT = PROJECT_ROOT / "信息抽取+数据检验/Django123/atc_extractor/backend"
BACKEND_API_URL = "http://127.0.0.1:8000/api"
class TestRunner:
def __init__(self):
self.test_results = {
'static_analysis': {},
'api_tests': {},
'database_tests': {},
'security_tests': {},
'integration_tests': {}
}
self.issues_found = []
def run_static_analysis(self):
"""静态代码分析"""
print("🔍 进行静态代码分析...")
issues = []
# 1. 检查数据库凭据安全性
settings_file = DJANGO_ROOT / "backend/settings.py"
if settings_file.exists():
with open(settings_file, 'r', encoding='utf-8') as f:
content = f.read()
if 'hzk200407140238' in content:
issues.append({
'type': 'SECURITY',
'severity': 'HIGH',
'message': '数据库密码硬编码在源代码中',
'file': str(settings_file),
'recommendation': '使用环境变量或配置文件管理敏感信息'
})
if 'DEBUG = True' in content:
issues.append({
'type': 'SECURITY',
'severity': 'MEDIUM',
'message': 'DEBUG模式在生产环境中应该关闭',
'file': str(settings_file),
'recommendation': '在生产环境中设置DEBUG = False'
})
if 'django-insecure' in content:
issues.append({
'type': 'SECURITY',
'severity': 'HIGH',
'message': '使用默认的不安全SECRET_KEY',
'file': str(settings_file),
'recommendation': '生成新的安全SECRET_KEY'
})
# 2. 检查表名拼写错误
views_file = DJANGO_ROOT / "extractor/views.py"
if views_file.exists():
with open(views_file, 'r', encoding='utf-8') as f:
content = f.read()
if 'precessed_table' in content:
issues.append({
'type': 'BUG',
'severity': 'HIGH',
'message': '表名拼写错误: precessed_table 应该是 processed_table',
'file': str(views_file),
'recommendation': '修正表名拼写或确保数据库中表名一致'
})
# 3. 检查模型文件是否为空
models_file = DJANGO_ROOT / "extractor/models.py"
if models_file.exists():
with open(models_file, 'r', encoding='utf-8') as f:
content = f.read().strip()
if len(content) < 100: # 基本上是空文件
issues.append({
'type': 'ARCHITECTURE',
'severity': 'MEDIUM',
'message': 'models.py文件为空未使用Django ORM',
'file': str(models_file),
'recommendation': '考虑使用Django ORM管理数据模型或添加注释说明原因'
})
# 4. 检查依赖管理
requirements_file = DJANGO_ROOT / "requirements.txt"
if not requirements_file.exists():
issues.append({
'type': 'DEPLOYMENT',
'severity': 'MEDIUM',
'message': '缺少requirements.txt文件',
'file': str(DJANGO_ROOT),
'recommendation': '创建requirements.txt管理项目依赖'
})
self.test_results['static_analysis'] = {
'issues_count': len(issues),
'issues': issues
}
self.issues_found.extend(issues)
print(f" 发现 {len(issues)} 个静态分析问题")
return issues
def test_api_endpoints(self):
"""测试API接口"""
print("🌐 测试API接口...")
endpoints = [
('GET', '/health/', '健康检查'),
('GET', '/original-data/', '原始数据获取'),
('GET', '/statistics/', '统计信息'),
('GET', '/processed-data/', '处理后数据'),
('POST', '/preprocess/', '数据预处理'),
('POST', '/merge/', '格式合并'),
('POST', '/correct/', '单词纠错'),
('POST', '/analyze/', '大模型分析'),
('POST', '/upload/', '文件上传'),
]
results = {}
for method, endpoint, description in endpoints:
try:
url = f"{BACKEND_API_URL}{endpoint}"
if method == 'GET':
response = requests.get(url, timeout=5)
else:
# POST请求发送空JSON
response = requests.post(url, json={}, timeout=5)
results[endpoint] = {
'status_code': response.status_code,
'success': response.status_code in [200, 400], # 400也可能是正常的业务错误
'description': description,
'response_size': len(response.content)
}
if response.status_code == 200:
print(f"{description} ({endpoint}): {response.status_code}")
elif response.status_code == 400:
print(f"{description} ({endpoint}): {response.status_code} (业务错误)")
else:
print(f"{description} ({endpoint}): {response.status_code}")
except requests.RequestException as e:
results[endpoint] = {
'error': str(e),
'success': False,
'description': description
}
print(f"{description} ({endpoint}): 连接失败 - {e}")
self.test_results['api_tests'] = results
return results
def test_database_connectivity(self):
"""测试数据库连接"""
print("🗄️ 测试数据库连接...")
# 通过API测试数据库连接
try:
response = requests.get(f"{BACKEND_API_URL}/statistics/", timeout=5)
if response.status_code == 200:
data = response.json()
if data.get('status') == 'success':
print(" ✓ 数据库连接正常")
return True
print(" ✗ 数据库连接异常")
return False
except Exception as e:
print(f" ✗ 数据库连接测试失败: {e}")
return False
def check_server_status(self):
"""检查Django服务器状态"""
print("🚀 检查Django服务器状态...")
try:
response = requests.get(f"{BACKEND_API_URL}/health/", timeout=3)
if response.status_code == 200:
print(" ✓ Django服务器运行正常")
return True
else:
print(f" ✗ Django服务器响应异常: {response.status_code}")
return False
except requests.RequestException:
print(" ✗ Django服务器未运行或无法连接")
print(" 💡 请先启动Django服务器: python manage.py runserver")
return False
def generate_test_report(self):
"""生成测试报告"""
print("\n" + "="*60)
print("📊 测试报告汇总")
print("="*60)
# 静态分析结果
static_issues = self.test_results['static_analysis'].get('issues', [])
print(f"\n🔍 静态分析: 发现 {len(static_issues)} 个问题")
for issue in static_issues:
severity_emoji = {
'HIGH': '🔴',
'MEDIUM': '🟡',
'LOW': '🟢'
}.get(issue['severity'], '')
print(f" {severity_emoji} [{issue['type']}] {issue['message']}")
print(f" 文件: {issue['file']}")
print(f" 建议: {issue['recommendation']}")
print()
# API测试结果
api_results = self.test_results['api_tests']
successful_apis = sum(1 for r in api_results.values() if r.get('success', False))
print(f"\n🌐 API测试: {successful_apis}/{len(api_results)} 个接口正常")
for endpoint, result in api_results.items():
if result.get('success'):
print(f"{result['description']}: {result.get('status_code', 'OK')}")
else:
print(f"{result['description']}: {result.get('error', result.get('status_code', '未知错误'))}")
# 生成修复建议
self.generate_fix_recommendations()
# 保存详细报告
report_file = PROJECT_ROOT / "test" / "test_report.json"
with open(report_file, 'w', encoding='utf-8') as f:
json.dump(self.test_results, f, indent=2, ensure_ascii=False)
print(f"\n📄 详细报告已保存到: {report_file}")
def generate_fix_recommendations(self):
"""生成修复建议"""
print("\n" + "="*60)
print("🔧 修复建议")
print("="*60)
high_priority_issues = [
issue for issue in self.issues_found
if issue.get('severity') == 'HIGH'
]
if high_priority_issues:
print("\n🔴 高优先级问题(需要立即修复):")
for i, issue in enumerate(high_priority_issues, 1):
print(f"\n{i}. {issue['message']}")
print(f" 类型: {issue['type']}")
print(f" 文件: {issue['file']}")
print(f" 建议: {issue['recommendation']}")
# 通用修复建议
print("\n💡 通用优化建议:")
print("1. 创建环境变量配置文件 (.env)")
print("2. 添加单元测试覆盖所有API接口")
print("3. 实现日志记录和监控")
print("4. 添加数据验证和错误处理")
print("5. 考虑使用Django ORM替代原生SQL")
print("6. 添加API文档Swagger/OpenAPI")
print("7. 实现缓存机制提高性能")
print("8. 添加数据库迁移管理")
def run_all_tests(self):
"""运行所有测试"""
print("🚀 开始综合测试...")
# 1. 检查服务器状态
if not self.check_server_status():
print("\n❌ 服务器未运行跳过API测试")
print("请先启动Django服务器:")
print(f"cd {DJANGO_ROOT}")
print("python manage.py runserver")
# 只运行静态分析
self.run_static_analysis()
else:
# 2. 静态分析
self.run_static_analysis()
# 3. API测试
self.test_api_endpoints()
# 4. 数据库测试
self.test_database_connectivity()
# 5. 生成报告
self.generate_test_report()
def main():
"""主函数"""
print("🎯 Django后端测试系统")
print("=" * 60)
runner = TestRunner()
runner.run_all_tests()
print("\n✅ 测试完成!")
# 检查是否有严重问题
high_issues = sum(1 for issue in runner.issues_found if issue.get('severity') == 'HIGH')
if high_issues > 0:
print(f"⚠️ 发现 {high_issues} 个高优先级问题需要修复")
return 1
else:
print("🎉 未发现严重问题")
return 0
if __name__ == "__main__":
sys.exit(main())