Files
qiaoxinjiu 6994b185a3 addproject
2026-01-22 19:10:37 +08:00

329 lines
10 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
统一测试执行文件
支持批量运行所有用例、按标签运行、按目录运行等
"""
import os
import sys
import subprocess
import argparse
from pathlib import Path
# 添加项目根目录到 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)
# 测试目录
TEST_CASE_DIR = 'zhyy/test_case/TestCase'
# 报告目录
REPORT_DIR = os.path.join(os.path.dirname(current_file_path), 'reports')
ALLURE_RESULTS_DIR = os.path.join(REPORT_DIR, 'allure-results')
ALLURE_REPORT_DIR = os.path.join(REPORT_DIR, 'allure-report')
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命令"""
# 基础pytest命令
# 设置PYTHONPATH环境变量确保能导入zhyy模块
env = os.environ.copy()
if 'PYTHONPATH' in env:
env['PYTHONPATH'] = project_root + os.pathsep + env['PYTHONPATH']
else:
env['PYTHONPATH'] = project_root
# 检测是否在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()
cmd = ['python', '-m', 'pytest'] + args_list
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
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
return test_files
def run_all_tests():
"""运行所有测试用例"""
print("运行所有测试用例...")
# 递归查找所有测试文件
test_files = find_test_files(TEST_CASE_DIR)
if not test_files:
print("未找到测试文件")
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'
]
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))
return 0
except subprocess.CalledProcessError as e:
print("生成Allure报告失败: {}".format(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]
try:
# 使用shell=True来执行命令确保使用正确的环境变量
subprocess.Popen(' '.join(cmd), shell=True)
print("Allure报告已在浏览器中打开")
except FileNotFoundError:
print("警告: 未找到allure命令请先安装allure")
def main():
parser = argparse.ArgumentParser(
description='统一测试执行工具',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
使用示例:
# 运行所有测试
python run_tests.py --all
# 按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
"""
)
# 运行选项(不强制要求,默认运行所有测试)
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('--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报告默认会生成')
args = parser.parse_args()
# 确保目录存在
ensure_dirs()
# 执行测试(如果没有指定选项,默认运行所有测试)
exit_code = 0
if args.feature:
exit_code = run_by_feature(args.feature)
elif args.story:
exit_code = run_by_story(args.story)
elif args.dir:
exit_code = run_by_dir(args.dir)
elif args.file:
exit_code = run_by_file(args.file)
elif args.keyword:
exit_code = run_by_keyword(args.keyword)
elif args.marker:
exit_code = run_by_marker(args.marker)
else:
# 默认运行所有测试
exit_code = run_all_tests()
# 生成报告
if args.report or (not args.no_report and exit_code == 0):
generate_allure_report()
if args.open:
open_allure_report()
print("=" * 80)
if exit_code == 0:
print("✓ 测试执行完成")
else:
print("✗ 测试执行失败,退出码: {}".format(exit_code))
print("=" * 80)
sys.exit(exit_code)
if __name__ == '__main__':
main()