736 lines
28 KiB
Python
736 lines
28 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
简化版无头浏览器测试
|
|
使用requests和备用方法进行模块测试
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import json
|
|
import requests
|
|
import logging
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Dict, List, Tuple, Optional
|
|
from urllib.parse import urljoin
|
|
|
|
# 配置日志
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
handlers=[
|
|
logging.FileHandler('simple_headless_test.log'),
|
|
logging.StreamHandler()
|
|
]
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class SimpleHeadlessTester:
|
|
"""简化版无头测试器"""
|
|
|
|
def __init__(self, base_url: str = "http://localhost:8000"):
|
|
self.base_url = base_url
|
|
self.session = requests.Session()
|
|
self.session.headers.update({
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
|
})
|
|
self.test_results = []
|
|
self.test_data_dir = Path("test_data")
|
|
self.test_data_dir.mkdir(exist_ok=True)
|
|
|
|
def test_url(self, url: str, module: str, test_name: str,
|
|
expected_status: int = 200, check_content: List[str] = None) -> Dict:
|
|
"""测试URL访问"""
|
|
try:
|
|
start_time = time.time()
|
|
response = self.session.get(url, timeout=10)
|
|
elapsed = (time.time() - start_time) * 1000
|
|
|
|
# 检查状态码
|
|
if response.status_code == expected_status:
|
|
passed = True
|
|
details = f"状态码: {response.status_code}, 响应时间: {elapsed:.1f}ms"
|
|
|
|
# 检查内容
|
|
if check_content:
|
|
content = response.text
|
|
missing = []
|
|
for keyword in check_content:
|
|
if keyword not in content:
|
|
missing.append(keyword)
|
|
passed = False
|
|
|
|
if missing:
|
|
details = f"缺少关键词: {', '.join(missing)}"
|
|
else:
|
|
details = f"包含所有关键词, 响应时间: {elapsed:.1f}ms"
|
|
else:
|
|
passed = False
|
|
details = f"期望状态码 {expected_status}, 实际 {response.status_code}"
|
|
|
|
# 记录结果
|
|
result = self.record_test_result(module, test_name, passed, details)
|
|
|
|
# 保存响应内容
|
|
if not passed:
|
|
self.save_test_data(f"{module}_{test_name}_failed.html", response.text)
|
|
|
|
return result
|
|
|
|
except Exception as e:
|
|
details = f"请求失败: {e}"
|
|
return self.record_test_result(module, test_name, False, details)
|
|
|
|
def test_api_json(self, url: str, module: str, test_name: str,
|
|
check_fields: List[str] = None, api_type: str = "wanandroid") -> Dict:
|
|
"""测试API JSON响应
|
|
|
|
Args:
|
|
url: API地址
|
|
module: 模块名称
|
|
test_name: 测试名称
|
|
check_fields: 需要检查的字段
|
|
api_type: API类型,'wanandroid'或'health'
|
|
"""
|
|
try:
|
|
response = self.session.get(url, timeout=10)
|
|
|
|
if response.status_code == 200:
|
|
try:
|
|
data = response.json()
|
|
|
|
# 检查必需字段
|
|
if check_fields:
|
|
missing = []
|
|
for field in check_fields:
|
|
if field not in data:
|
|
missing.append(field)
|
|
|
|
if missing:
|
|
details = f"缺少字段: {', '.join(missing)}"
|
|
return self.record_test_result(module, test_name, False, details)
|
|
|
|
# 根据API类型检查格式
|
|
if api_type == "wanandroid":
|
|
# 玩Android API格式
|
|
if 'errorCode' in data and data['errorCode'] == 0:
|
|
details = f"API格式正确, errorCode: {data['errorCode']}"
|
|
return self.record_test_result(module, test_name, True, details)
|
|
else:
|
|
details = f"API错误码: {data.get('errorCode', '未知')}"
|
|
return self.record_test_result(module, test_name, False, details)
|
|
elif api_type == "health":
|
|
# 健康检查API格式
|
|
if 'status' in data and data['status'] == 'healthy':
|
|
details = f"健康检查正常, 状态: {data['status']}"
|
|
return self.record_test_result(module, test_name, True, details)
|
|
else:
|
|
details = f"健康状态异常: {data.get('status', '未知')}"
|
|
return self.record_test_result(module, test_name, False, details)
|
|
else:
|
|
# 通用API检查
|
|
details = f"API响应正常, 状态码: {response.status_code}"
|
|
return self.record_test_result(module, test_name, True, details)
|
|
|
|
except json.JSONDecodeError as e:
|
|
details = f"JSON解析失败: {e}"
|
|
return self.record_test_result(module, test_name, False, details)
|
|
else:
|
|
details = f"HTTP状态码: {response.status_code}"
|
|
return self.record_test_result(module, test_name, False, details)
|
|
|
|
except Exception as e:
|
|
details = f"API测试失败: {e}"
|
|
return self.record_test_result(module, test_name, False, details)
|
|
|
|
def record_test_result(self, module: str, test_name: str, passed: bool,
|
|
details: str = "") -> Dict:
|
|
"""记录测试结果"""
|
|
result = {
|
|
"module": module,
|
|
"test_name": test_name,
|
|
"passed": passed,
|
|
"timestamp": datetime.now().isoformat(),
|
|
"details": details
|
|
}
|
|
self.test_results.append(result)
|
|
|
|
status = "✅" if passed else "❌"
|
|
logger.info(f"{status} {module} - {test_name}: {details}")
|
|
|
|
return result
|
|
|
|
def save_test_data(self, filename: str, content: str):
|
|
"""保存测试数据"""
|
|
filepath = self.test_data_dir / filename
|
|
with open(filepath, 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
logger.debug(f"📄 测试数据保存: {filepath}")
|
|
|
|
def test_module_homepage(self) -> Dict:
|
|
"""测试首页模块"""
|
|
module = "首页模块"
|
|
results = []
|
|
|
|
# 测试首页访问
|
|
result = self.test_url(
|
|
urljoin(self.base_url, "/"),
|
|
module,
|
|
"首页访问",
|
|
check_content=["玩Android", "Material Design", "文章列表"]
|
|
)
|
|
results.append(result)
|
|
|
|
# 测试Material Design元素
|
|
result = self.test_url(
|
|
urljoin(self.base_url, "/"),
|
|
module,
|
|
"Material元素",
|
|
check_content=["search-container", "banner", "tab-bar"]
|
|
)
|
|
results.append(result)
|
|
|
|
# 测试CSS样式
|
|
result = self.test_url(
|
|
urljoin(self.base_url, "/"),
|
|
module,
|
|
"CSS样式",
|
|
check_content=["6200EE", "03DAC6", "Roboto"]
|
|
)
|
|
results.append(result)
|
|
|
|
return {
|
|
"module": module,
|
|
"total_tests": len(results),
|
|
"passed": sum(1 for r in results if r["passed"]),
|
|
"failed": sum(1 for r in results if not r["passed"]),
|
|
"results": results
|
|
}
|
|
|
|
def test_module_material_preview(self) -> Dict:
|
|
"""测试Material预览模块"""
|
|
module = "Material预览模块"
|
|
results = []
|
|
|
|
# 测试Material预览页面
|
|
result = self.test_url(
|
|
urljoin(self.base_url, "/material_preview.html"),
|
|
module,
|
|
"预览页面访问",
|
|
check_content=["Material Design", "颜色系统", "图标系统", "组件系统"]
|
|
)
|
|
results.append(result)
|
|
|
|
# 测试颜色系统
|
|
result = self.test_url(
|
|
urljoin(self.base_url, "/material_preview.html"),
|
|
module,
|
|
"颜色系统",
|
|
check_content=["color-swatch", "primary-color", "secondary-color", "Color System"]
|
|
)
|
|
results.append(result)
|
|
|
|
# 测试响应式设计
|
|
result = self.test_url(
|
|
urljoin(self.base_url, "/material_preview.html"),
|
|
module,
|
|
"响应式设计",
|
|
check_content=["@media", "max-width"]
|
|
)
|
|
results.append(result)
|
|
|
|
return {
|
|
"module": module,
|
|
"total_tests": len(results),
|
|
"passed": sum(1 for r in results if r["passed"]),
|
|
"failed": sum(1 for r in results if not r["passed"]),
|
|
"results": results
|
|
}
|
|
|
|
def test_module_api(self) -> Dict:
|
|
"""测试API接口模块"""
|
|
module = "API接口模块"
|
|
results = []
|
|
|
|
# 测试健康检查API
|
|
result = self.test_api_json(
|
|
urljoin(self.base_url, "/health"),
|
|
module,
|
|
"健康检查API",
|
|
check_fields=["status", "timestamp", "service"],
|
|
api_type="health"
|
|
)
|
|
results.append(result)
|
|
|
|
# 测试Banner API
|
|
result = self.test_api_json(
|
|
urljoin(self.base_url, "/api/banner/json"),
|
|
module,
|
|
"Banner API",
|
|
check_fields=["errorCode", "data"]
|
|
)
|
|
results.append(result)
|
|
|
|
# 测试文章列表API
|
|
result = self.test_api_json(
|
|
urljoin(self.base_url, "/api/article/list/0/json"),
|
|
module,
|
|
"文章列表API",
|
|
check_fields=["errorCode", "data"]
|
|
)
|
|
results.append(result)
|
|
|
|
# 测试热词API
|
|
result = self.test_api_json(
|
|
urljoin(self.base_url, "/api/hotkey/json"),
|
|
module,
|
|
"热词API",
|
|
check_fields=["errorCode", "data"]
|
|
)
|
|
results.append(result)
|
|
|
|
return {
|
|
"module": module,
|
|
"total_tests": len(results),
|
|
"passed": sum(1 for r in results if r["passed"]),
|
|
"failed": sum(1 for r in results if not r["passed"]),
|
|
"results": results
|
|
}
|
|
|
|
def test_module_quick_test(self) -> Dict:
|
|
"""测试快速测试页面模块"""
|
|
module = "快速测试页面模块"
|
|
results = []
|
|
|
|
# 测试快速测试页面
|
|
result = self.test_url(
|
|
urljoin(self.base_url, "/quick_test.html"),
|
|
module,
|
|
"快速测试页面访问",
|
|
check_content=["快速测试", "测试按钮", "服务器信息", "test-button", "按钮集合"]
|
|
)
|
|
results.append(result)
|
|
|
|
# 测试按钮功能
|
|
result = self.test_url(
|
|
urljoin(self.base_url, "/quick_test.html"),
|
|
module,
|
|
"测试按钮",
|
|
check_content=["test-button", "button-icon", "访问首页", "Material预览"]
|
|
)
|
|
results.append(result)
|
|
|
|
# 测试服务器信息显示
|
|
result = self.test_url(
|
|
urljoin(self.base_url, "/quick_test.html"),
|
|
module,
|
|
"服务器信息",
|
|
check_content=["服务器地址", "129.211.173.87", "运行时长", "测试状态"]
|
|
)
|
|
results.append(result)
|
|
|
|
return {
|
|
"module": module,
|
|
"total_tests": len(results),
|
|
"passed": sum(1 for r in results if r["passed"]),
|
|
"failed": sum(1 for r in results if not r["passed"]),
|
|
"results": results
|
|
}
|
|
|
|
def test_module_uniapp_structure(self) -> Dict:
|
|
"""测试Uniapp项目结构模块"""
|
|
module = "Uniapp结构模块"
|
|
results = []
|
|
|
|
# 检查项目文件结构
|
|
project_files = [
|
|
("pages/", "目录存在", True),
|
|
("pages/index/index.vue", "首页文件", True),
|
|
("pages/project/project.vue", "项目页面", True),
|
|
("pages/official/official.vue", "公众号页面", True),
|
|
("pages/system/system.vue", "体系页面", True),
|
|
("pages/mine/mine.vue", "我的页面", True),
|
|
("static/images/icons/", "图标目录", True),
|
|
("manifest.json", "配置文件", True),
|
|
("pages.json", "路由配置", True),
|
|
("App.vue", "应用配置", True),
|
|
]
|
|
|
|
for filepath, description, required in project_files:
|
|
exists = Path(filepath).exists()
|
|
passed = exists if required else True
|
|
|
|
result = self.record_test_result(
|
|
module,
|
|
description,
|
|
passed,
|
|
f"{filepath} {'存在' if exists else '不存在'}"
|
|
)
|
|
results.append(result)
|
|
|
|
# 检查Material图标
|
|
icons_dir = Path("static/images/icons")
|
|
if icons_dir.exists():
|
|
icon_count = len(list(icons_dir.glob("*")))
|
|
result = self.record_test_result(
|
|
module,
|
|
"Material图标",
|
|
icon_count >= 5,
|
|
f"找到{icon_count}个图标文件"
|
|
)
|
|
results.append(result)
|
|
|
|
return {
|
|
"module": module,
|
|
"total_tests": len(results),
|
|
"passed": sum(1 for r in results if r["passed"]),
|
|
"failed": sum(1 for r in results if not r["passed"]),
|
|
"results": results
|
|
}
|
|
|
|
def test_module_performance(self) -> Dict:
|
|
"""测试性能模块"""
|
|
module = "性能测试模块"
|
|
results = []
|
|
|
|
# 测试首页性能
|
|
start_time = time.time()
|
|
try:
|
|
response = self.session.get(urljoin(self.base_url, "/"), timeout=10)
|
|
elapsed = (time.time() - start_time) * 1000
|
|
|
|
if response.status_code == 200:
|
|
passed = elapsed < 1000 # 1秒内响应
|
|
result = self.record_test_result(
|
|
module,
|
|
"首页响应时间",
|
|
passed,
|
|
f"响应时间: {elapsed:.1f}ms"
|
|
)
|
|
results.append(result)
|
|
else:
|
|
result = self.record_test_result(
|
|
module,
|
|
"首页响应时间",
|
|
False,
|
|
f"HTTP状态码: {response.status_code}"
|
|
)
|
|
results.append(result)
|
|
except Exception as e:
|
|
result = self.record_test_result(
|
|
module,
|
|
"首页响应时间",
|
|
False,
|
|
f"请求失败: {e}"
|
|
)
|
|
results.append(result)
|
|
|
|
# 测试API性能
|
|
apis_to_test = [
|
|
("/health", "健康检查API"),
|
|
("/api/banner/json", "Banner API"),
|
|
("/api/hotkey/json", "热词API"),
|
|
]
|
|
|
|
for api_path, api_name in apis_to_test:
|
|
start_time = time.time()
|
|
try:
|
|
response = self.session.get(urljoin(self.base_url, api_path), timeout=10)
|
|
elapsed = (time.time() - start_time) * 1000
|
|
|
|
if response.status_code == 200:
|
|
passed = elapsed < 500 # 500ms内响应
|
|
result = self.record_test_result(
|
|
module,
|
|
f"{api_name}响应时间",
|
|
passed,
|
|
f"响应时间: {elapsed:.1f}ms"
|
|
)
|
|
results.append(result)
|
|
else:
|
|
result = self.record_test_result(
|
|
module,
|
|
f"{api_name}响应时间",
|
|
False,
|
|
f"HTTP状态码: {response.status_code}"
|
|
)
|
|
results.append(result)
|
|
except Exception as e:
|
|
result = self.record_test_result(
|
|
module,
|
|
f"{api_name}响应时间",
|
|
False,
|
|
f"请求失败: {e}"
|
|
)
|
|
results.append(result)
|
|
|
|
return {
|
|
"module": module,
|
|
"total_tests": len(results),
|
|
"passed": sum(1 for r in results if r["passed"]),
|
|
"failed": sum(1 for r in results if not r["passed"]),
|
|
"results": results
|
|
}
|
|
|
|
def run_all_tests(self) -> Dict:
|
|
"""运行所有测试"""
|
|
logger.info("🚀 开始简化版无头浏览器测试")
|
|
logger.info(f"📡 测试地址: {self.base_url}")
|
|
logger.info(f"⏰ 开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
|
|
all_results = []
|
|
|
|
# 运行各个模块测试
|
|
test_modules = [
|
|
("首页模块", self.test_module_homepage),
|
|
("Material预览模块", self.test_module_material_preview),
|
|
("API接口模块", self.test_module_api),
|
|
("快速测试页面模块", self.test_module_quick_test),
|
|
("Uniapp结构模块", self.test_module_uniapp_structure),
|
|
("性能测试模块", self.test_module_performance),
|
|
]
|
|
|
|
for module_name, test_func in test_modules:
|
|
logger.info(f"\n🔍 开始测试: {module_name}")
|
|
result = test_func()
|
|
all_results.append(result)
|
|
logger.info(f"📊 {module_name}测试完成: {result['passed']}/{result['total_tests']} 通过")
|
|
|
|
# 生成测试报告
|
|
report = self.generate_test_report(all_results)
|
|
|
|
return report
|
|
|
|
def generate_test_report(self, all_results: List[Dict]) -> Dict:
|
|
"""生成测试报告"""
|
|
total_tests = sum(r.get("total_tests", 0) for r in all_results)
|
|
total_passed = sum(r.get("passed", 0) for r in all_results)
|
|
total_failed = sum(r.get("failed", 0) for r in all_results)
|
|
|
|
report = {
|
|
"timestamp": datetime.now().isoformat(),
|
|
"base_url": self.base_url,
|
|
"total_modules": len(all_results),
|
|
"total_tests": total_tests,
|
|
"total_passed": total_passed,
|
|
"total_failed": total_failed,
|
|
"success_rate": (total_passed / total_tests * 100) if total_tests > 0 else 0,
|
|
"modules": all_results,
|
|
"summary": self._generate_summary(all_results)
|
|
}
|
|
|
|
# 保存报告到文件
|
|
report_file = "simple_headless_test_report.json"
|
|
with open(report_file, "w", encoding="utf-8") as f:
|
|
json.dump(report, f, ensure_ascii=False, indent=2)
|
|
|
|
# 生成HTML报告
|
|
self._generate_html_report(report)
|
|
|
|
logger.info(f"\n🎯 测试完成!")
|
|
logger.info(f"📊 总体结果: {total_passed}/{total_tests} 通过 ({report['success_rate']:.1f}%)")
|
|
logger.info(f"📄 详细报告: {report_file}")
|
|
logger.info(f"📄 HTML报告: simple_headless_test_report.html")
|
|
|
|
return report
|
|
|
|
def _generate_summary(self, all_results: List[Dict]) -> str:
|
|
"""生成测试摘要"""
|
|
summary_lines = []
|
|
|
|
for module_result in all_results:
|
|
module_name = module_result.get("module", "未知模块")
|
|
passed = module_result.get("passed", 0)
|
|
total = module_result.get("total_tests", 0)
|
|
|
|
if total > 0:
|
|
percentage = (passed / total) * 100
|
|
status = "✅" if percentage >= 80 else "⚠️" if percentage >= 50 else "❌"
|
|
summary_lines.append(f"{status} {module_name}: {passed}/{total} ({percentage:.1f}%)")
|
|
else:
|
|
summary_lines.append(f"❌ {module_name}: 0/0 (无测试)")
|
|
|
|
return "\n".join(summary_lines)
|
|
|
|
def _generate_html_report(self, report: Dict):
|
|
"""生成HTML测试报告"""
|
|
html_content = f"""
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>简化版无头浏览器测试报告</title>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<style>
|
|
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
|
|
body {{ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f5f5f5; color: #333; line-height: 1.6; padding: 20px; }}
|
|
|
|
.container {{ max-width: 1200px; margin: 0 auto; }}
|
|
|
|
.header {{ background: linear-gradient(135deg, #6200EE 0%, #3700B3 100%); color: white; padding: 40px; border-radius: 15px; margin-bottom: 30px; text-align: center; }}
|
|
.header h1 {{ font-size: 36px; margin-bottom: 10px; }}
|
|
.header .subtitle {{ font-size: 18px; opacity: 0.9; }}
|
|
|
|
.summary-card {{ background: white; border-radius: 15px; padding: 30px; margin-bottom: 30px; box-shadow: 0 5px 15px rgba(0,0,0,0.1); }}
|
|
.summary-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-top: 20px; }}
|
|
.summary-item {{ text-align: center; padding: 20px; border-radius: 10px; }}
|
|
.summary-item.total {{ background: #e3f2fd; }}
|
|
.summary-item.passed {{ background: #e8f5e9; }}
|
|
.summary-item.failed {{ background: #ffebee; }}
|
|
.summary-item.rate {{ background: #fff3e0; }}
|
|
.summary-value {{ font-size: 32px; font-weight: bold; margin-bottom: 5px; }}
|
|
.summary-label {{ font-size: 14px; color: #666; }}
|
|
|
|
.module-section {{ margin-bottom: 30px; }}
|
|
.module-header {{ background: #6200EE; color: white; padding: 15px 20px; border-radius: 10px 10px 0 0; display: flex; justify-content: space-between; align-items: center; }}
|
|
.module-title {{ font-size: 20px; font-weight: 500; }}
|
|
.module-stats {{ font-size: 16px; }}
|
|
|
|
.test-results {{ background: white; border-radius: 0 0 10px 10px; padding: 20px; box-shadow: 0 3px 10px rgba(0,0,0,0.1); }}
|
|
.test-item {{ padding: 15px; border-bottom: 1px solid #eee; display: flex; align-items: center; }}
|
|
.test-item:last-child {{ border-bottom: none; }}
|
|
.test-status {{ font-size: 24px; margin-right: 15px; width: 40px; text-align: center; }}
|
|
.test-details {{ flex: 1; }}
|
|
.test-name {{ font-weight: 500; margin-bottom: 5px; }}
|
|
.test-info {{ font-size: 14px; color: #666; }}
|
|
|
|
.footer {{ text-align: center; margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; color: #666; font-size: 14px; }}
|
|
|
|
@media (max-width: 768px) {{
|
|
.summary-grid {{ grid-template-columns: 1fr; }}
|
|
}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<h1>🎯 简化版无头浏览器测试报告</h1>
|
|
<div class="subtitle">玩Android Material Design开发服务器</div>
|
|
<div class="subtitle">测试时间: {report['timestamp']}</div>
|
|
<div class="subtitle">测试地址: {report['base_url']}</div>
|
|
</div>
|
|
|
|
<div class="summary-card">
|
|
<h2>📊 测试概览</h2>
|
|
<div class="summary-grid">
|
|
<div class="summary-item total">
|
|
<div class="summary-value">{report['total_modules']}</div>
|
|
<div class="summary-label">测试模块</div>
|
|
</div>
|
|
<div class="summary-item total">
|
|
<div class="summary-value">{report['total_tests']}</div>
|
|
<div class="summary-label">总测试数</div>
|
|
</div>
|
|
<div class="summary-item passed">
|
|
<div class="summary-value">{report['total_passed']}</div>
|
|
<div class="summary-label">通过测试</div>
|
|
</div>
|
|
<div class="summary-item failed">
|
|
<div class="summary-value">{report['total_failed']}</div>
|
|
<div class="summary-label">失败测试</div>
|
|
</div>
|
|
<div class="summary-item rate">
|
|
<div class="summary-value">{report['success_rate']:.1f}%</div>
|
|
<div class="summary-label">通过率</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="summary-card">
|
|
<h2>🔍 测试摘要</h2>
|
|
<pre style="background: #f5f5f5; padding: 15px; border-radius: 8px; margin-top: 10px; white-space: pre-wrap; font-family: monospace;">{report['summary']}</pre>
|
|
</div>
|
|
|
|
<h2 style="margin: 30px 0 20px 0;">📋 详细测试结果</h2>
|
|
|
|
{self._generate_module_html(report['modules'])}
|
|
|
|
<div class="footer">
|
|
<p>© 2026 玩Android Material Design测试报告 | 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
|
|
<p>测试方法: Requests库 + 内容分析</p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
with open("simple_headless_test_report.html", "w", encoding="utf-8") as f:
|
|
f.write(html_content)
|
|
|
|
def _generate_module_html(self, modules: List[Dict]) -> str:
|
|
"""生成模块测试结果的HTML"""
|
|
html_parts = []
|
|
|
|
for module in modules:
|
|
module_name = module.get("module", "未知模块")
|
|
passed = module.get("passed", 0)
|
|
total = module.get("total_tests", 0)
|
|
results = module.get("results", [])
|
|
|
|
# 计算通过率
|
|
percentage = (passed / total * 100) if total > 0 else 0
|
|
|
|
# 模块头部
|
|
html_parts.append(f"""
|
|
<div class="module-section">
|
|
<div class="module-header">
|
|
<div class="module-title">{module_name}</div>
|
|
<div class="module-stats">{passed}/{total} 通过 ({percentage:.1f}%)</div>
|
|
</div>
|
|
<div class="test-results">
|
|
""")
|
|
|
|
# 测试结果
|
|
for result in results:
|
|
status = "✅" if result.get("passed", False) else "❌"
|
|
test_name = result.get("test_name", "未知测试")
|
|
details = result.get("details", "")
|
|
|
|
html_parts.append(f"""
|
|
<div class="test-item">
|
|
<div class="test-status">{status}</div>
|
|
<div class="test-details">
|
|
<div class="test-name">{test_name}</div>
|
|
<div class="test-info">{details}</div>
|
|
</div>
|
|
</div>
|
|
""")
|
|
|
|
html_parts.append("""
|
|
</div>
|
|
</div>
|
|
""")
|
|
|
|
return "\n".join(html_parts)
|
|
|
|
def main():
|
|
"""主函数"""
|
|
print("🚀 玩Android Material Design简化版无头浏览器测试")
|
|
print("="*60)
|
|
|
|
# 创建测试器
|
|
tester = SimpleHeadlessTester(base_url="http://localhost:8000")
|
|
|
|
# 运行测试
|
|
report = tester.run_all_tests()
|
|
|
|
# 输出结果
|
|
print(f"\n🎯 测试完成!")
|
|
print(f"📊 总体结果: {report['total_passed']}/{report['total_tests']} 通过 ({report['success_rate']:.1f}%)")
|
|
print(f"📄 JSON报告: simple_headless_test_report.json")
|
|
print(f"📄 HTML报告: simple_headless_test_report.html")
|
|
print(f"📝 日志文件: simple_headless_test.log")
|
|
|
|
if report['success_rate'] >= 80:
|
|
print("✅ 测试通过!")
|
|
sys.exit(0)
|
|
elif report['success_rate'] >= 50:
|
|
print("⚠️ 测试部分通过,需要改进")
|
|
sys.exit(1)
|
|
else:
|
|
print("❌ 测试失败!")
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main() |