#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ E2E/UAT 测试启动脚本 用于启动整个后台系统的端到端测试和用户验收测试 支持在开发环境直接运行,无需 Docker 部署 """ import os import sys import subprocess import argparse from pathlib import Path def parse_args(): """解析命令行参数""" parser = argparse.ArgumentParser(description='E2E/UAT 测试启动脚本') parser.add_argument( '--env', type=str, default='dev', choices=['dev', 'test', 'prod'], help='运行环境 (默认: dev)' ) parser.add_argument( '--database', type=str, default='h2', choices=['h2', 'postgresql'], help='测试数据库类型 (默认: h2)' ) parser.add_argument( '--backend-url', type=str, default='http://localhost:8084', help='后端服务地址 (默认: http://localhost:8084)' ) parser.add_argument( '--frontend-url', type=str, default='http://localhost:3000', help='前端服务地址 (默认: http://localhost:3000)' ) parser.add_argument( '--test-dir', type=str, default='test-suite/api', help='测试目录路径 (默认: test-suite/api)' ) parser.add_argument( '--test-case', type=str, default=None, help='指定要运行的测试用例文件或类 (默认: 运行所有测试)' ) parser.add_argument( '--parallel', action='store_true', help='启用并行测试' ) parser.add_argument( '--reruns', type=int, default=0, help='失败用例重跑次数 (默认: 0)' ) parser.add_argument( '--html-report', type=str, default='test-suite/report.html', help='HTML 测试报告路径 (默认: test-suite/report.html)' ) parser.add_argument( '--junit-report', type=str, default='test-suite/junit.xml', help='JUnit 测试报告路径 (默认: test-suite/junit.xml)' ) parser.add_argument( '--verbose', action='store_true', help='启用详细输出模式' ) parser.add_argument( '--coverage', action='store_true', help='启用代码覆盖率报告' ) parser.add_argument( '--dry-run', action='store_true', help='仅打印命令,不实际执行' ) return parser.parse_args() def check_dependencies(): """检查依赖是否安装""" required_packages = [ 'pytest', 'pytest-html', 'pytest-rerunfailures', 'pytest-asyncio', 'requests', 'pytest-dependency' ] missing_packages = [] for package in required_packages: try: __import__(package.replace('-', '_')) except ImportError: missing_packages.append(package) if missing_packages: print("❌ 缺少必要的 Python 包,请运行:") print(f" pip install {' '.join(missing_packages)}") sys.exit(1) def setup_environment(args): """设置环境变量""" env_vars = { 'ENV': args.env, 'DATABASE': args.database, 'BASE_URL': args.backend_url, 'FRONTEND_URL': args.frontend_url, 'TEST_MODE': 'true' } for key, value in env_vars.items(): os.environ[key] = value print(f"✅ 环境变量已设置:") for key, value in env_vars.items(): print(f" {key}={value}") def run_pytest(args): """运行 pytest 测试""" cmd = [ sys.executable, '-m', 'pytest', args.test_dir, f'--html={args.html_report}', f'--junitxml={args.junit_report}', '--self-contained-html' ] if args.verbose: cmd.append('-v') if args.parallel: cmd.extend(['-n', 'auto']) if args.reruns > 0: cmd.extend(['--reruns', str(args.reruns)]) if args.test_case: cmd.append(args.test_case) if args.coverage: cmd.extend([ '--cov=test_suite', '--cov-report=html:test-suite/coverage', '--cov-report=term' ]) print(f"\n🚀 运行测试命令:") print(f" {' '.join(cmd)}\n") if args.dry_run: print("✅ 干运行模式,测试未执行") return 0 result = subprocess.run(cmd) return result.returncode def main(): """主函数""" args = parse_args() print("=" * 60) print("🔧 E2E/UAT 测试启动脚本") print("=" * 60) # 检查依赖 print("\n📦 检查依赖...") check_dependencies() print("✅ 依赖检查通过") # 设置环境 print("\n⚙️ 设置环境...") setup_environment(args) # 运行测试 print("\n🧪 运行测试...") exit_code = run_pytest(args) # 输出结果 print("\n" + "=" * 60) if exit_code == 0: print("✅ 测试全部通过!") else: print(f"❌ 测试失败 (退出码: {exit_code})") print("=" * 60) # 输出报告路径 print(f"\n📊 测试报告:") print(f" HTML: file://{os.path.abspath(args.html_report)}") print(f" JUnit: {os.path.abspath(args.junit_report)}") if args.coverage: print(f" Coverage: file://{os.path.abspath('test-suite/coverage/index.html')}") sys.exit(exit_code) if __name__ == '__main__': main()