#!/usr/bin/env python3 """ CI/CD 测试脚本 用于持续集成环境中的测试执行 """ import os import sys import json import time from pathlib import Path from datetime import datetime # 添加项目路径 project_root = Path(__file__).parent.parent sys.path.insert(0, str(project_root)) from config.settings import get_settings from utils.logger import get_logger class CITestRunner: """CI测试运行器""" def __init__(self): self.logger = get_logger() self.settings = get_settings() self.results = { "timestamp": datetime.now().isoformat(), "environment": os.environ.get("ENVIRONMENT", "development"), "browser": os.environ.get("PLAYWRIGHT_BROWSER", "chromium"), "tests": [], "summary": { "total": 0, "passed": 0, "failed": 0, "skipped": 0, "error": 0, "duration": 0 } } def run_smoke_tests(self) -> bool: """运行冒烟测试""" self.logger.section("运行冒烟测试") from playwright.sync_api import sync_playwright import pytest pytest_args = [ "-c", str(project_root / "pytest.ini"), "-m", "smoke", "-v", "--tb=short", "--json-report", "--json-report-file=reports/smoke_test_results.json", "tests" ] try: exit_code = pytest.main(pytest_args) return exit_code == 0 except Exception as e: self.logger.error(f"冒烟测试失败: {e}") return False def run_regression_tests(self) -> bool: """运行回归测试""" self.logger.section("运行回归测试") import pytest pytest_args = [ "-c", str(project_root / "pytest.ini"), "-m", "regression", "-v", "--tb=short", "--json-report", "--json-report-file=reports/regression_test_results.json", "tests" ] try: exit_code = pytest.main(pytest_args) return exit_code == 0 except Exception as e: self.logger.error(f"回归测试失败: {e}") return False def run_performance_tests(self) -> bool: """运行性能测试""" self.logger.section("运行性能测试") import pytest pytest_args = [ "-c", str(project_root / "pytest.ini"), "-m", "performance", "-v", "--tb=short", "--json-report", "--json-report-file=reports/performance_test_results.json", "tests" ] try: exit_code = pytest.main(pytest_args) return exit_code == 0 except Exception as e: self.logger.error(f"性能测试失败: {e}") return False def run_cross_browser_tests(self) -> dict: """运行跨浏览器测试""" self.logger.section("运行跨浏览器测试") import pytest browsers = ["chromium", "firefox", "webkit"] results = {} for browser in browsers: self.logger.info(f"测试浏览器: {browser}") os.environ["PLAYWRIGHT_BROWSER"] = browser pytest_args = [ "-c", str(project_root / "pytest.ini"), "-m", "smoke", "-v", "--tb=short", f"--json-report=reports/{browser}_test_results.json", "tests" ] try: exit_code = pytest.main(pytest_args) results[browser] = exit_code == 0 except Exception as e: self.logger.error(f"{browser} 测试失败: {e}") results[browser] = False return results def run_full_test_suite(self) -> bool: """运行完整测试套件""" self.logger.section("运行完整测试套件") import pytest pytest_args = [ "-c", str(project_root / "pytest.ini"), "-v", "--tb=short", "--json-report", "--json-report-file=reports/full_test_results.json", "--html=reports/full_test_report.html", "--self-contained-html", "tests" ] try: exit_code = pytest.main(pytest_args) return exit_code == 0 except Exception as e: self.logger.error(f"完整测试失败: {e}") return False def generate_ci_report(self, test_results: dict): """生成CI测试报告""" report_path = Path("reports/ci_test_report.json") report_path.parent.mkdir(parents=True, exist_ok=True) with open(report_path, "w", encoding="utf-8") as f: json.dump(test_results, f, indent=2, ensure_ascii=False) self.logger.info(f"CI报告已生成: {report_path}") def run_ci_tests(self, test_type: str = "full"): """运行CI测试""" start_time = time.time() self.logger.section("开始 CI 测试") self.logger.info(f"环境: {self.results['environment']}") self.logger.info(f"浏览器: {self.results['browser']}") self.logger.info(f"测试类型: {test_type}") success = False if test_type == "smoke": success = self.run_smoke_tests() elif test_type == "regression": success = self.run_regression_tests() elif test_type == "performance": success = self.run_performance_tests() elif test_type == "cross_browser": cross_results = self.run_cross_browser_tests() success = all(cross_results.values()) self.results["cross_browser_results"] = cross_results elif test_type == "full": success = self.run_full_test_suite() else: self.logger.error(f"未知的测试类型: {test_type}") return False end_time = time.time() self.results["summary"]["duration"] = end_time - start_time self.results["success"] = success self.logger.section("CI 测试完成") self.logger.info(f"总耗时: {self.results['summary']['duration']:.2f}秒") self.logger.info(f"测试结果: {'成功' if success else '失败'}") # 生成报告 self.generate_ci_report(self.results) return success def parse_ci_arguments(): """解析CI参数""" parser = argparse.ArgumentParser( description="Novalon Website CI 测试运行器" ) parser.add_argument( "--test-type", default="full", choices=["smoke", "regression", "performance", "cross_browser", "full"], help="测试类型 (默认: full)" ) parser.add_argument( "--env", default="development", choices=["development", "staging", "production"], help="测试环境 (默认: development)" ) parser.add_argument( "--browser", default="chromium", choices=["chromium", "firefox", "webkit", "all"], help="浏览器 (默认: chromium)" ) parser.add_argument( "--report-dir", default="reports", help="报告目录 (默认: reports)" ) return parser.parse_args() def main(): """CI主函数""" args = parse_ci_arguments() # 设置环境变量 os.environ["ENVIRONMENT"] = args.env os.environ["PLAYWRIGHT_BROWSER"] = args.browser os.environ["REPORT_DIR"] = args.report_dir # 确保报告目录存在 Path(args.report_dir).mkdir(parents=True, exist_ok=True) # 运行测试 runner = CITestRunner() success = runner.run_ci_tests(args.test_type) # 输出结果 if success: print("\n✅ CI 测试通过") sys.exit(0) else: print("\n❌ CI 测试失败") sys.exit(1) if __name__ == "__main__": main()