From 36525b264c6ff1496056c0d31d17e4d8aa800a82 Mon Sep 17 00:00:00 2001 From: qiaoxinjiu Date: Thu, 19 Mar 2026 19:44:49 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=B7=AF=E5=BE=84=E5=9C=B0?= =?UTF-8?q?=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zhyy/test_case/run_tests.py | 296 ++++++++++++------------------------ 1 file changed, 99 insertions(+), 197 deletions(-) diff --git a/zhyy/test_case/run_tests.py b/zhyy/test_case/run_tests.py index 63a53fd..564f0ca 100644 --- a/zhyy/test_case/run_tests.py +++ b/zhyy/test_case/run_tests.py @@ -3,11 +3,10 @@ 统一测试执行文件 支持批量运行所有用例、按标签运行、按目录运行等 """ -import os -import sys -import subprocess import argparse -from pathlib import Path +import os +import subprocess +import sys # 添加项目根目录到 Python 路径 current_file_path = os.path.abspath(__file__) @@ -15,8 +14,10 @@ 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(REPORT_DIR, 'allure-results') @@ -31,43 +32,23 @@ def ensure_dirs(): def run_pytest(args_list): """执行pytest命令""" - # 基础pytest命令 - # 设置PYTHONPATH环境变量,确保能导入zhyy模块 + # 设置PYTHONPATH环境变量 env = os.environ.copy() - if 'PYTHONPATH' in env: - env['PYTHONPATH'] = project_root + os.pathsep + env['PYTHONPATH'] - else: - env['PYTHONPATH'] = project_root + env['PYTHONPATH'] = project_root + (os.pathsep + env['PYTHONPATH'] if 'PYTHONPATH' in env else '') - # 检测是否在Jenkins环境中 + # 检测Jenkins环境 is_jenkins = 'JENKINS_URL' in env or 'BUILD_NUMBER' in env - if is_jenkins: - print("检测到Jenkins环境,使用Jenkins配置...") - # 在Jenkins中,报告路径使用绝对路径 - if 'WORKSPACE' in env: - workspace = env['WORKSPACE'] - # 确保使用Jenkins工作空间的报告目录 - global ALLURE_RESULTS_DIR, ALLURE_REPORT_DIR - ALLURE_RESULTS_DIR = os.path.join(workspace, 'zhyy', 'test_case', 'reports', 'allure-results') - ALLURE_REPORT_DIR = os.path.join(workspace, 'zhyy', 'test_case', 'reports', 'allure-report') - ensure_dirs() + 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)}") - print("=" * 80) - print("执行命令: {}".format(' '.join(cmd))) - print("命令列表: {}".format(cmd)) - print("测试目录: {}".format(TEST_CASE_DIR)) - print("测试目录是否存在: {}".format(os.path.exists(TEST_CASE_DIR))) - if is_jenkins: - print("Jenkins工作空间: {}".format(env.get('WORKSPACE', 'N/A'))) - print("构建编号: {}".format(env.get('BUILD_NUMBER', 'N/A'))) - print("PYTHONPATH: {}".format(env.get('PYTHONPATH'))) - print("Allure结果目录: {}".format(ALLURE_RESULTS_DIR)) - print("当前工作目录: {}".format(os.getcwd())) - print("=" * 80) - - # 使用 shell=True 来执行命令,确保能正确处理路径和参数 + # 执行命令 result = subprocess.run(' '.join(cmd), shell=True, cwd=project_root, env=env) return result.returncode @@ -77,162 +58,100 @@ def find_test_files(directory): test_files = [] for root, dirs, files in os.walk(directory): for file in files: - if file.endswith('.py'): - # 检查文件中是否包含测试函数 - file_path = os.path.join(root, file) - try: - with open(file_path, 'r', encoding='utf-8') as f: - content = f.read() - if 'def test_' in content or 'class Test' in content: - test_files.append(file_path) - except: - pass + if file.endswith('.py') and not file.startswith('__'): + test_files.append(os.path.join(root, file)) return test_files -def run_all_tests(): - """运行所有测试用例""" - print("运行所有测试用例...") - # 递归查找所有测试文件 - test_files = find_test_files(TEST_CASE_DIR) - if not test_files: - print("未找到测试文件") +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 - print(f"找到 {len(test_files)} 个测试文件:") - for file in test_files: - print(f" - {file}") - - args = [ - *test_files, - '-v', # 详细输出 - '--tb=short', # 简短的错误信息 - f'--alluredir={ALLURE_RESULTS_DIR}', # allure结果目录 - ] - return run_pytest(args) - - -def run_by_feature(feature_name): - """按allure feature标签运行""" - print("按feature标签运行: {}".format(feature_name)) - args = [ - TEST_CASE_DIR, - '-v', - '--tb=short', - f'--allure-features={feature_name}', - f'--alluredir={ALLURE_RESULTS_DIR}', - ] - return run_pytest(args) - - -def run_by_story(story_name): - """按allure story标签运行""" - print("按story标签运行: {}".format(story_name)) - args = [ - TEST_CASE_DIR, - '-v', - '--tb=short', - f'--allure-stories={story_name}', - f'--alluredir={ALLURE_RESULTS_DIR}', - ] - return run_pytest(args) - - -def run_by_marker(marker): - """按pytest标记运行""" - print("按pytest标记运行: {}".format(marker)) - args = [ - TEST_CASE_DIR, - '-v', - '--tb=short', - f'-m={marker}', - f'--alluredir={ALLURE_RESULTS_DIR}', - ] - return run_pytest(args) - - -def run_by_dir(directory): - """按目录运行""" - full_path = os.path.join(TEST_CASE_DIR, directory) - if not os.path.exists(full_path): - print("错误: 目录不存在: {}".format(full_path)) - return 1 - - print("按目录运行: {}".format(directory)) - args = [ - full_path, - '-v', - '--tb=short', - f'--alluredir={ALLURE_RESULTS_DIR}', - ] - return run_pytest(args) - - -def run_by_file(file_path): - """按文件运行""" - full_path = os.path.join(TEST_CASE_DIR, file_path) - if not os.path.exists(full_path): - print("错误: 文件不存在: {}".format(full_path)) - return 1 - - print("按文件运行: {}".format(file_path)) - args = [ - full_path, - '-v', - '--tb=short', - f'--alluredir={ALLURE_RESULTS_DIR}', - ] - return run_pytest(args) - - -def run_by_keyword(keyword): - """按关键字运行(匹配文件名或类名)""" - print("按关键字运行: {}".format(keyword)) - args = [ - TEST_CASE_DIR, - '-v', - '--tb=short', - f'-k={keyword}', - f'--alluredir={ALLURE_RESULTS_DIR}', - ] return run_pytest(args) def generate_allure_report(): """生成allure报告""" print("生成Allure报告...") - cmd = [ - 'allure', - 'generate', - ALLURE_RESULTS_DIR, - '-o', - ALLURE_REPORT_DIR, - '--clean' - ] + cmd = f'allure generate {ALLURE_RESULTS_DIR} -o {ALLURE_REPORT_DIR} --clean' try: - # 使用shell=True来执行命令,确保使用正确的环境变量 - result = subprocess.run(' '.join(cmd), shell=True, check=True) - print("Allure报告生成成功: {}".format(ALLURE_REPORT_DIR)) - print("打开报告命令: allure open {}".format(ALLURE_REPORT_DIR)) + 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("生成Allure报告失败: {}".format(e)) + print(f"生成Allure报告失败: {e}") return 1 except FileNotFoundError: print("警告: 未找到allure命令,请先安装allure") - print("安装方法: https://docs.qameta.io/allure/") return 1 def open_allure_report(): """打开allure报告""" print("打开Allure报告...") - cmd = ['allure', 'open', ALLURE_REPORT_DIR] + cmd = f'allure open {ALLURE_REPORT_DIR}' try: - # 使用shell=True来执行命令,确保使用正确的环境变量 - subprocess.Popen(' '.join(cmd), shell=True) + subprocess.Popen(cmd, shell=True) print("Allure报告已在浏览器中打开") except FileNotFoundError: print("警告: 未找到allure命令,请先安装allure") @@ -241,72 +160,58 @@ def open_allure_report(): def main(): parser = argparse.ArgumentParser( description='统一测试执行工具', - formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" 使用示例: # 运行所有测试 - python run_tests.py --all + python run_tests.py # 按feature标签运行 python run_tests.py --feature "深圳采购工作台采购订单页面" - # 按story标签运行 - python run_tests.py --story "验证采购工作台采购订单页面列表查询" - # 按目录运行 python run_tests.py --dir "接口/SZPurchase" - # 按文件运行 - python run_tests.py --file "接口/SZPurchase/PurchaseOrderManage.py" - - # 按关键字运行 - python run_tests.py --keyword "purchase" - - # 按pytest标记运行 - python run_tests.py --marker "smoke" - # 生成并打开报告 - python run_tests.py --all --report --open + python run_tests.py --report --open """ ) - # 运行选项(不强制要求,默认运行所有测试) + # 运行选项 run_group = parser.add_mutually_exclusive_group(required=False) - run_group.add_argument('--all', action='store_true', help='运行所有测试用例(默认)') 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('--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报告(需要先使用--report)') - parser.add_argument('--no-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_by_feature(args.feature) + exit_code = run_tests(args.feature, 'feature') elif args.story: - exit_code = run_by_story(args.story) + exit_code = run_tests(args.story, 'story') elif args.dir: - exit_code = run_by_dir(args.dir) + exit_code = run_tests(args.dir, 'dir') elif args.file: - exit_code = run_by_file(args.file) + exit_code = run_tests(args.file, 'file') elif args.keyword: - exit_code = run_by_keyword(args.keyword) + exit_code = run_tests(args.keyword, 'keyword') elif args.marker: - exit_code = run_by_marker(args.marker) + exit_code = run_tests(args.marker, 'marker') else: # 默认运行所有测试 - exit_code = run_all_tests() + exit_code = run_tests(None, 'all') # 生成报告 if args.report or (not args.no_report and exit_code == 0): @@ -315,10 +220,7 @@ def main(): open_allure_report() print("=" * 80) - if exit_code == 0: - print("✓ 测试执行完成") - else: - print("✗ 测试执行失败,退出码: {}".format(exit_code)) + print("✓ 测试执行完成" if exit_code == 0 else f"✗ 测试执行失败,退出码: {exit_code}") print("=" * 80) sys.exit(exit_code)