Showing
2 changed files
with
238 additions
and
2 deletions
| 1 | { | 1 | { |
| 2 | - "token": "eyJhbGciOiJIUzUxMiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwic3ViIjoiYWRtaW4iLCJpYXQiOjE3NjAzMjYxMTksImV4cCI6MTc2MDQxMjUxOX0.QiJRc8xCQN_MBEwH3BRK5fUW17pz_9s7fCvFJK1AIbqg8uqhezw-FVxUi7G5-gIf4zlJrovZpMB0VGg7xT3XDg", | 2 | + "token": "eyJhbGciOiJIUzUxMiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwic3ViIjoiYWRtaW4iLCJpYXQiOjE3NjAzMjY2OTIsImV4cCI6MTc2MDQxMzA5Mn0.g_bbqdvMIIoPws2bOC8AJpFHYo-zSFgybXAEJUF3rvheltchQG1q_jZZSSw2tWLQvZOjzFeJxOROJwKbu5JnIQ", |
| 3 | - "saved_at": 1760326119 | 3 | + "saved_at": 1760326692 |
| 4 | } | 4 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -7,6 +7,203 @@ Python 3.7.8 兼容 | ... | @@ -7,6 +7,203 @@ Python 3.7.8 兼容 |
| 7 | 7 | ||
| 8 | import os | 8 | import os |
| 9 | import sys | 9 | import sys |
| 10 | +import json | ||
| 11 | +import time | ||
| 12 | +from datetime import datetime | ||
| 13 | +from typing import Dict, List, Any | ||
| 14 | + | ||
| 15 | +class TestReporter: | ||
| 16 | + """测试报告生成器""" | ||
| 17 | + | ||
| 18 | + def __init__(self): | ||
| 19 | + self.test_results = [] | ||
| 20 | + self.start_time = None | ||
| 21 | + self.end_time = None | ||
| 22 | + | ||
| 23 | + def start_test_suite(self): | ||
| 24 | + """开始测试套件""" | ||
| 25 | + self.start_time = datetime.now() | ||
| 26 | + | ||
| 27 | + def end_test_suite(self): | ||
| 28 | + """结束测试套件""" | ||
| 29 | + self.end_time = datetime.now() | ||
| 30 | + | ||
| 31 | + def add_test_result(self, test_name: str, script_name: str, success: bool, | ||
| 32 | + execution_time: float, error_message: str = None, | ||
| 33 | + output: str = None): | ||
| 34 | + """添加测试结果""" | ||
| 35 | + result = { | ||
| 36 | + 'test_name': test_name, | ||
| 37 | + 'script_name': script_name, | ||
| 38 | + 'success': success, | ||
| 39 | + 'execution_time': execution_time, | ||
| 40 | + 'error_message': error_message, | ||
| 41 | + 'output': output, | ||
| 42 | + 'timestamp': datetime.now().isoformat() | ||
| 43 | + } | ||
| 44 | + self.test_results.append(result) | ||
| 45 | + | ||
| 46 | + def generate_html_report(self, output_file: str = None): | ||
| 47 | + """生成HTML格式的测试报告""" | ||
| 48 | + if output_file is None: | ||
| 49 | + # 确保reports目录存在 | ||
| 50 | + reports_dir = "reports" | ||
| 51 | + if not os.path.exists(reports_dir): | ||
| 52 | + os.makedirs(reports_dir) | ||
| 53 | + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | ||
| 54 | + output_file = os.path.join(reports_dir, f"test_report_{timestamp}.html") | ||
| 55 | + | ||
| 56 | + total_tests = len(self.test_results) | ||
| 57 | + passed_tests = sum(1 for r in self.test_results if r['success']) | ||
| 58 | + failed_tests = total_tests - passed_tests | ||
| 59 | + success_rate = (passed_tests / total_tests * 100) if total_tests > 0 else 0 | ||
| 60 | + | ||
| 61 | + total_time = (self.end_time - self.start_time).total_seconds() if self.end_time and self.start_time else 0 | ||
| 62 | + | ||
| 63 | + html_content = f""" | ||
| 64 | +<!DOCTYPE html> | ||
| 65 | +<html lang="zh-CN"> | ||
| 66 | +<head> | ||
| 67 | + <meta charset="UTF-8"> | ||
| 68 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| 69 | + <title>Apple ERP API 测试报告</title> | ||
| 70 | + <style> | ||
| 71 | + body {{ font-family: 'Microsoft YaHei', Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }} | ||
| 72 | + .container {{ max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }} | ||
| 73 | + .header {{ text-align: center; margin-bottom: 30px; }} | ||
| 74 | + .header h1 {{ color: #333; margin-bottom: 10px; }} | ||
| 75 | + .header .timestamp {{ color: #666; font-size: 14px; }} | ||
| 76 | + .summary {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px; }} | ||
| 77 | + .summary-card {{ background: #f8f9fa; padding: 20px; border-radius: 6px; text-align: center; border-left: 4px solid #007bff; }} | ||
| 78 | + .summary-card.success {{ border-left-color: #28a745; }} | ||
| 79 | + .summary-card.failure {{ border-left-color: #dc3545; }} | ||
| 80 | + .summary-card h3 {{ margin: 0 0 10px 0; color: #333; }} | ||
| 81 | + .summary-card .number {{ font-size: 2em; font-weight: bold; color: #007bff; }} | ||
| 82 | + .summary-card.success .number {{ color: #28a745; }} | ||
| 83 | + .summary-card.failure .number {{ color: #dc3545; }} | ||
| 84 | + .test-results {{ margin-top: 30px; }} | ||
| 85 | + .test-item {{ margin-bottom: 20px; padding: 15px; border-radius: 6px; border: 1px solid #ddd; }} | ||
| 86 | + .test-item.success {{ background: #d4edda; border-color: #c3e6cb; }} | ||
| 87 | + .test-item.failure {{ background: #f8d7da; border-color: #f5c6cb; }} | ||
| 88 | + .test-header {{ display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }} | ||
| 89 | + .test-name {{ font-weight: bold; font-size: 16px; }} | ||
| 90 | + .test-status {{ padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: bold; }} | ||
| 91 | + .test-status.success {{ background: #28a745; color: white; }} | ||
| 92 | + .test-status.failure {{ background: #dc3545; color: white; }} | ||
| 93 | + .test-details {{ font-size: 14px; color: #666; }} | ||
| 94 | + .test-output {{ background: #f8f9fa; padding: 10px; border-radius: 4px; margin-top: 10px; font-family: monospace; font-size: 12px; max-height: 200px; overflow-y: auto; }} | ||
| 95 | + .error-message {{ color: #dc3545; font-weight: bold; }} | ||
| 96 | + </style> | ||
| 97 | +</head> | ||
| 98 | +<body> | ||
| 99 | + <div class="container"> | ||
| 100 | + <div class="header"> | ||
| 101 | + <h1>🍎 Apple ERP API 测试报告</h1> | ||
| 102 | + <div class="timestamp">生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</div> | ||
| 103 | + </div> | ||
| 104 | + | ||
| 105 | + <div class="summary"> | ||
| 106 | + <div class="summary-card"> | ||
| 107 | + <h3>总测试数</h3> | ||
| 108 | + <div class="number">{total_tests}</div> | ||
| 109 | + </div> | ||
| 110 | + <div class="summary-card success"> | ||
| 111 | + <h3>通过测试</h3> | ||
| 112 | + <div class="number">{passed_tests}</div> | ||
| 113 | + </div> | ||
| 114 | + <div class="summary-card failure"> | ||
| 115 | + <h3>失败测试</h3> | ||
| 116 | + <div class="number">{failed_tests}</div> | ||
| 117 | + </div> | ||
| 118 | + <div class="summary-card"> | ||
| 119 | + <h3>成功率</h3> | ||
| 120 | + <div class="number">{success_rate:.1f}%</div> | ||
| 121 | + </div> | ||
| 122 | + <div class="summary-card"> | ||
| 123 | + <h3>执行时间</h3> | ||
| 124 | + <div class="number">{total_time:.2f}s</div> | ||
| 125 | + </div> | ||
| 126 | + </div> | ||
| 127 | + | ||
| 128 | + <div class="test-results"> | ||
| 129 | + <h2>详细测试结果</h2> | ||
| 130 | +""" | ||
| 131 | + | ||
| 132 | + for result in self.test_results: | ||
| 133 | + status_class = "success" if result['success'] else "failure" | ||
| 134 | + status_text = "✅ 通过" if result['success'] else "❌ 失败" | ||
| 135 | + | ||
| 136 | + html_content += f""" | ||
| 137 | + <div class="test-item {status_class}"> | ||
| 138 | + <div class="test-header"> | ||
| 139 | + <div class="test-name">{result['test_name']}</div> | ||
| 140 | + <div class="test-status {status_class}">{status_text}</div> | ||
| 141 | + </div> | ||
| 142 | + <div class="test-details"> | ||
| 143 | + <strong>脚本:</strong> {result['script_name']}<br> | ||
| 144 | + <strong>执行时间:</strong> {result['execution_time']:.2f}秒<br> | ||
| 145 | + <strong>时间戳:</strong> {result['timestamp']} | ||
| 146 | +""" | ||
| 147 | + | ||
| 148 | + if result['error_message']: | ||
| 149 | + html_content += f'<div class="error-message">错误信息: {result["error_message"]}</div>' | ||
| 150 | + | ||
| 151 | + if result['output']: | ||
| 152 | + html_content += f'<div class="test-output">{result["output"]}</div>' | ||
| 153 | + | ||
| 154 | + html_content += """ | ||
| 155 | + </div> | ||
| 156 | + </div> | ||
| 157 | +""" | ||
| 158 | + | ||
| 159 | + html_content += """ | ||
| 160 | + </div> | ||
| 161 | + </div> | ||
| 162 | +</body> | ||
| 163 | +</html> | ||
| 164 | +""" | ||
| 165 | + | ||
| 166 | + with open(output_file, 'w', encoding='utf-8') as f: | ||
| 167 | + f.write(html_content) | ||
| 168 | + | ||
| 169 | + return output_file | ||
| 170 | + | ||
| 171 | + def generate_json_report(self, output_file: str = None): | ||
| 172 | + """生成JSON格式的测试报告""" | ||
| 173 | + if output_file is None: | ||
| 174 | + # 确保reports目录存在 | ||
| 175 | + reports_dir = "reports" | ||
| 176 | + if not os.path.exists(reports_dir): | ||
| 177 | + os.makedirs(reports_dir) | ||
| 178 | + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | ||
| 179 | + output_file = os.path.join(reports_dir, f"test_report_{timestamp}.json") | ||
| 180 | + | ||
| 181 | + total_tests = len(self.test_results) | ||
| 182 | + passed_tests = sum(1 for r in self.test_results if r['success']) | ||
| 183 | + failed_tests = total_tests - passed_tests | ||
| 184 | + success_rate = (passed_tests / total_tests * 100) if total_tests > 0 else 0 | ||
| 185 | + | ||
| 186 | + total_time = (self.end_time - self.start_time).total_seconds() if self.end_time and self.start_time else 0 | ||
| 187 | + | ||
| 188 | + report_data = { | ||
| 189 | + 'test_suite': 'Apple ERP API Tests', | ||
| 190 | + 'generated_at': datetime.now().isoformat(), | ||
| 191 | + 'summary': { | ||
| 192 | + 'total_tests': total_tests, | ||
| 193 | + 'passed_tests': passed_tests, | ||
| 194 | + 'failed_tests': failed_tests, | ||
| 195 | + 'success_rate': success_rate, | ||
| 196 | + 'total_execution_time': total_time, | ||
| 197 | + 'start_time': self.start_time.isoformat() if self.start_time else None, | ||
| 198 | + 'end_time': self.end_time.isoformat() if self.end_time else None | ||
| 199 | + }, | ||
| 200 | + 'test_results': self.test_results | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + with open(output_file, 'w', encoding='utf-8') as f: | ||
| 204 | + json.dump(report_data, f, ensure_ascii=False, indent=2) | ||
| 205 | + | ||
| 206 | + return output_file | ||
| 10 | 207 | ||
| 11 | def main(): | 208 | def main(): |
| 12 | """主函数:按顺序运行所有测试""" | 209 | """主函数:按顺序运行所有测试""" |
| ... | @@ -14,6 +211,10 @@ def main(): | ... | @@ -14,6 +211,10 @@ def main(): |
| 14 | print("Apple ERP API 测试套件") | 211 | print("Apple ERP API 测试套件") |
| 15 | print("=" * 60) | 212 | print("=" * 60) |
| 16 | 213 | ||
| 214 | + # 初始化测试报告器 | ||
| 215 | + reporter = TestReporter() | ||
| 216 | + reporter.start_test_suite() | ||
| 217 | + | ||
| 17 | # 测试脚本列表(按执行顺序) | 218 | # 测试脚本列表(按执行顺序) |
| 18 | tests = [ | 219 | tests = [ |
| 19 | ("认证登录测试", "test_auth.py"), | 220 | ("认证登录测试", "test_auth.py"), |
| ... | @@ -31,8 +232,15 @@ def main(): | ... | @@ -31,8 +232,15 @@ def main(): |
| 31 | 232 | ||
| 32 | if not os.path.exists(script_name): | 233 | if not os.path.exists(script_name): |
| 33 | print(f"❌ 脚本不存在: {script_name}") | 234 | print(f"❌ 脚本不存在: {script_name}") |
| 235 | + reporter.add_test_result(test_name, script_name, False, 0, | ||
| 236 | + f"脚本不存在: {script_name}") | ||
| 34 | continue | 237 | continue |
| 35 | 238 | ||
| 239 | + start_time = time.time() | ||
| 240 | + test_output = [] | ||
| 241 | + error_message = None | ||
| 242 | + test_success = False | ||
| 243 | + | ||
| 36 | try: | 244 | try: |
| 37 | # 直接导入并运行测试函数 | 245 | # 直接导入并运行测试函数 |
| 38 | module_name = script_name.replace('.py', '') | 246 | module_name = script_name.replace('.py', '') |
| ... | @@ -42,36 +250,64 @@ def main(): | ... | @@ -42,36 +250,64 @@ def main(): |
| 42 | if success: | 250 | if success: |
| 43 | print(f"✅ {test_name} 执行成功") | 251 | print(f"✅ {test_name} 执行成功") |
| 44 | success_count += 1 | 252 | success_count += 1 |
| 253 | + test_success = True | ||
| 45 | else: | 254 | else: |
| 46 | print(f"❌ {test_name} 执行失败") | 255 | print(f"❌ {test_name} 执行失败") |
| 256 | + error_message = "登录失败" | ||
| 47 | elif module_name == 'test_users': | 257 | elif module_name == 'test_users': |
| 48 | from test_users import run_user_tests | 258 | from test_users import run_user_tests |
| 49 | run_user_tests() | 259 | run_user_tests() |
| 50 | print(f"✅ {test_name} 执行成功") | 260 | print(f"✅ {test_name} 执行成功") |
| 51 | success_count += 1 | 261 | success_count += 1 |
| 262 | + test_success = True | ||
| 52 | elif module_name == 'test_roles': | 263 | elif module_name == 'test_roles': |
| 53 | from test_roles import run_role_tests | 264 | from test_roles import run_role_tests |
| 54 | run_role_tests() | 265 | run_role_tests() |
| 55 | print(f"✅ {test_name} 执行成功") | 266 | print(f"✅ {test_name} 执行成功") |
| 56 | success_count += 1 | 267 | success_count += 1 |
| 268 | + test_success = True | ||
| 57 | elif module_name == 'test_menus': | 269 | elif module_name == 'test_menus': |
| 58 | from test_menus import run_menu_tests | 270 | from test_menus import run_menu_tests |
| 59 | run_menu_tests() | 271 | run_menu_tests() |
| 60 | print(f"✅ {test_name} 执行成功") | 272 | print(f"✅ {test_name} 执行成功") |
| 61 | success_count += 1 | 273 | success_count += 1 |
| 274 | + test_success = True | ||
| 62 | elif module_name == 'test_dicts': | 275 | elif module_name == 'test_dicts': |
| 63 | from test_dicts import run_dict_tests | 276 | from test_dicts import run_dict_tests |
| 64 | run_dict_tests() | 277 | run_dict_tests() |
| 65 | print(f"✅ {test_name} 执行成功") | 278 | print(f"✅ {test_name} 执行成功") |
| 66 | success_count += 1 | 279 | success_count += 1 |
| 280 | + test_success = True | ||
| 281 | + | ||
| 67 | except Exception as e: | 282 | except Exception as e: |
| 68 | print(f"❌ {test_name} 执行失败: {e}") | 283 | print(f"❌ {test_name} 执行失败: {e}") |
| 284 | + error_message = str(e) | ||
| 285 | + | ||
| 286 | + execution_time = time.time() - start_time | ||
| 287 | + reporter.add_test_result(test_name, script_name, test_success, | ||
| 288 | + execution_time, error_message, | ||
| 289 | + '\n'.join(test_output) if test_output else None) | ||
| 290 | + | ||
| 291 | + # 结束测试套件 | ||
| 292 | + reporter.end_test_suite() | ||
| 69 | 293 | ||
| 70 | # 总结 | 294 | # 总结 |
| 71 | print("\n" + "=" * 60) | 295 | print("\n" + "=" * 60) |
| 72 | print(f"测试完成: {success_count}/{total_count} 个测试通过") | 296 | print(f"测试完成: {success_count}/{total_count} 个测试通过") |
| 73 | print("=" * 60) | 297 | print("=" * 60) |
| 74 | 298 | ||
| 299 | + # 生成测试报告 | ||
| 300 | + try: | ||
| 301 | + html_report = reporter.generate_html_report() | ||
| 302 | + json_report = reporter.generate_json_report() | ||
| 303 | + | ||
| 304 | + print(f"\n📊 测试报告已生成:") | ||
| 305 | + print(f" HTML报告: {html_report}") | ||
| 306 | + print(f" JSON报告: {json_report}") | ||
| 307 | + | ||
| 308 | + except Exception as e: | ||
| 309 | + print(f"⚠️ 生成测试报告时出错: {e}") | ||
| 310 | + | ||
| 75 | if success_count == total_count: | 311 | if success_count == total_count: |
| 76 | print("🎉 所有测试都通过了!") | 312 | print("🎉 所有测试都通过了!") |
| 77 | return 0 | 313 | return 0 | ... | ... |
-
Please register or login to post a comment