# -*- coding: utf-8 -*- """ 统一测试执行文件 支持批量运行所有用例、按标签运行、按目录运行等 """ import argparse import os import subprocess import sys # 添加项目根目录到 Python 路径 current_file_path = os.path.abspath(__file__) project_root = os.path.abspath(os.path.join(os.path.dirname(current_file_path), '../../')) if project_root not in sys.path: sys.path.insert(0, project_root) print(project_root) # 测试目录 TEST_CASE_DIR = 'zhyy/test_case/TestCase' case_dir = os.path.join(project_root,TEST_CASE_DIR) # 报告目录 REPORT_DIR = os.path.join(os.path.dirname(current_file_path), 'reports') ALLURE_RESULTS_DIR = os.path.join(project_root, 'allure-results') ALLURE_REPORT_DIR = os.path.join(project_root, 'allure-report') print(ALLURE_REPORT_DIR) def ensure_dirs(): """确保报告目录存在""" os.makedirs(ALLURE_RESULTS_DIR, exist_ok=True) os.makedirs(ALLURE_REPORT_DIR, exist_ok=True) def run_pytest(args_list): """执行pytest命令""" # 设置PYTHONPATH环境变量 env = os.environ.copy() env['PYTHONPATH'] = project_root + (os.pathsep + env['PYTHONPATH'] if 'PYTHONPATH' in env else '') # 检测Jenkins环境 is_jenkins = 'JENKINS_URL' in env or 'BUILD_NUMBER' in env if is_jenkins and 'WORKSPACE' in env: # Jenkins环境下使用绝对路径 global ALLURE_RESULTS_DIR, ALLURE_REPORT_DIR ALLURE_RESULTS_DIR = os.path.join(env['WORKSPACE'], 'zhyy', 'test_case', 'reports', 'allure-results') ALLURE_REPORT_DIR = os.path.join(env['WORKSPACE'], 'zhyy', 'test_case', 'reports', 'allure-report') ensure_dirs() cmd = ['python', '-m', 'pytest'] + args_list print(f"执行命令: {' '.join(cmd)}") # 执行命令 result = subprocess.run(' '.join(cmd), shell=True, cwd=project_root, env=env) return result.returncode def find_test_files(directory): """递归查找所有测试文件""" test_files = [] for root, dirs, files in os.walk(directory): for file in files: if file.endswith('.py') and not file.startswith('__'): test_files.append(os.path.join(root, file)) return test_files def run_tests(target, test_type='all', **kwargs): """运行测试""" base_args = ['-v', '--tb=short', f'--alluredir={ALLURE_RESULTS_DIR}'] if test_type == 'all': print("运行所有测试用例...") test_files = find_test_files(case_dir) if not test_files: print("错误: 未找到测试文件") return 1 args = test_files + base_args elif test_type == 'feature': print(f"按feature标签运行: {target}") test_files = find_test_files(case_dir) if not test_files: print("错误: 未找到测试文件") return 1 args = test_files + [f'--allure-features={target}'] + base_args elif test_type == 'story': print(f"按story标签运行: {target}") test_files = find_test_files(case_dir) if not test_files: print("错误: 未找到测试文件") return 1 args = test_files + [f'--allure-stories={target}'] + base_args elif test_type == 'marker': print(f"按pytest标记运行: {target}") test_files = find_test_files(case_dir) if not test_files: print("错误: 未找到测试文件") return 1 args = test_files + [f'-m={target}'] + base_args elif test_type == 'dir': full_path = os.path.join(case_dir, target) if not os.path.exists(full_path): print(f"错误: 目录不存在: {full_path}") return 1 print(f"按目录运行: {target}") test_files = find_test_files(full_path) if not test_files: print("错误: 未找到测试文件") return 1 args = test_files + base_args elif test_type == 'file': full_path = os.path.join(case_dir, target) if not os.path.exists(full_path): print(f"错误: 文件不存在: {full_path}") return 1 print(f"按文件运行: {target}") args = [full_path] + base_args elif test_type == 'keyword': print(f"按关键字运行: {target}") test_files = find_test_files(case_dir) if not test_files: print("错误: 未找到测试文件") return 1 args = test_files + [f'-k={target}'] + base_args else: print(f"错误: 未知的测试类型: {test_type}") return 1 return run_pytest(args) def generate_allure_report(): """生成allure报告""" print("生成Allure报告...") cmd = f'allure generate {ALLURE_RESULTS_DIR} -o {ALLURE_REPORT_DIR} --clean' try: subprocess.run(cmd, shell=True, check=True) print(f"Allure报告生成成功: {ALLURE_REPORT_DIR}") print(f"打开报告命令: allure open {ALLURE_REPORT_DIR}") return 0 except subprocess.CalledProcessError as e: print(f"生成Allure报告失败: {e}") return 1 except FileNotFoundError: print("警告: 未找到allure命令,请先安装allure") return 1 def open_allure_report(): """打开allure报告""" print("打开Allure报告...") cmd = f'allure open {ALLURE_REPORT_DIR}' try: subprocess.Popen(cmd, shell=True) print("Allure报告已在浏览器中打开") except FileNotFoundError: print("警告: 未找到allure命令,请先安装allure") def main(): parser = argparse.ArgumentParser( description='统一测试执行工具', epilog=""" 使用示例: # 运行所有测试 python run_tests.py # 按feature标签运行 python run_tests.py --feature "深圳采购工作台采购订单页面" # 按目录运行 python run_tests.py --dir "接口/SZPurchase" # 生成并打开报告 python run_tests.py --report --open """ ) # 运行选项 run_group = parser.add_mutually_exclusive_group(required=False) run_group.add_argument('--feature', type=str, help='按allure feature标签运行') run_group.add_argument('--story', type=str, help='按allure story标签运行') run_group.add_argument('--dir', type=str, help='按目录运行(相对于TestCase目录)') run_group.add_argument('--file', type=str, help='按文件运行(相对于TestCase目录)') run_group.add_argument('--keyword', type=str, help='按关键字运行') run_group.add_argument('--marker', type=str, help='按pytest标记运行') # 报告选项 parser.add_argument('--report', action='store_true', help='生成Allure报告') parser.add_argument('--open', action='store_true', help='打开Allure报告') parser.add_argument('--no-report', action='store_true', help='不生成Allure报告') args = parser.parse_args() # 确保目录存在 ensure_dirs() # 执行测试 exit_code = 0 if args.feature: exit_code = run_tests(args.feature, 'feature') elif args.story: exit_code = run_tests(args.story, 'story') elif args.dir: exit_code = run_tests(args.dir, 'dir') elif args.file: exit_code = run_tests(args.file, 'file') elif args.keyword: exit_code = run_tests(args.keyword, 'keyword') elif args.marker: exit_code = run_tests(args.marker, 'marker') else: # 默认运行所有测试 exit_code = run_tests(None, 'all') # 生成报告 if args.report or (not args.no_report and exit_code == 0): generate_allure_report() if args.open: open_allure_report() print("=" * 80) print("✓ 测试执行完成" if exit_code == 0 else f"✗ 测试执行失败,退出码: {exit_code}") print("=" * 80) sys.exit(exit_code) if __name__ == '__main__': main()