feat: 新增测试运行器脚本 run_tests.py

- 新增根目录 run_tests.py,自动根据测试类型加载依赖
- 支持所有测试类型:pdf/docx/xlsx/pptx/html/xls/doc/ppt/cli/core/utils/all
- 支持透传 pytest 参数(-v/--cov 等)
- 补全 advice_generator.py 中的 DocReader 和 PptReader 映射
- 更新 README.md,简化测试命令说明
This commit is contained in:
2026-03-16 23:14:28 +08:00
parent a490b2642c
commit 675235f5b3
4 changed files with 314 additions and 178 deletions

220
run_tests.py Normal file
View File

@@ -0,0 +1,220 @@
#!/usr/bin/env python3
"""测试运行器 - 自动根据测试类型加载依赖并运行 pytest"""
import argparse
import os
import shutil
import subprocess
import sys
from pathlib import Path
# 确定项目根目录和脚本路径
script_file = Path(__file__).resolve()
project_root = script_file.parent
scripts_dir = project_root / "scripts"
bootstrap_path = str(scripts_dir / "bootstrap.py")
# 将 scripts/ 目录添加到 sys.path
if str(scripts_dir) not in sys.path:
sys.path.append(str(scripts_dir))
# 抑制第三方库日志
os.environ["HF_HUB_DISABLE_PROGRESS_BARS"] = "1"
os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1"
os.environ["TQDM_DISABLE"] = "1"
# 测试类型映射
_TEST_TYPES = {
# 文件类型测试(有依赖配置)
"pdf": {"key": "pdf", "path": "tests/test_readers/test_pdf/"},
"docx": {"key": "docx", "path": "tests/test_readers/test_docx/"},
"xlsx": {"key": "xlsx", "path": "tests/test_readers/test_xlsx/"},
"pptx": {"key": "pptx", "path": "tests/test_readers/test_pptx/"},
"html": {"key": "html", "path": "tests/test_readers/test_html/"},
"xls": {"key": "xls", "path": "tests/test_readers/test_xls/"},
"doc": {"key": "doc", "path": "tests/test_readers/test_doc/"},
"ppt": {"key": "ppt", "path": "tests/test_readers/test_ppt/"},
# 核心测试(无特殊依赖)
"cli": {"key": None, "path": "tests/test_cli/"},
"core": {"key": None, "path": "tests/test_core/"},
"utils": {"key": None, "path": "tests/test_utils/"},
# 所有测试(合并所有依赖)
"all": {"key": "all", "path": "tests/"},
}
def get_dependencies_for_type(test_type: str, platform_id: str):
"""
获取指定测试类型的依赖配置。
Args:
test_type: 测试类型pdf/docx/.../all
platform_id: 平台标识
Returns:
(python_version, dependencies) 元组
"""
from config import DEPENDENCIES
config = _TEST_TYPES.get(test_type)
if not config:
return None, []
key = config["key"]
if key is None:
# 无特殊依赖的测试类型cli/core/utils
return None, []
if key == "all":
# 收集所有类型的依赖并去重
python_version = None
all_deps = set()
for type_key, type_config in DEPENDENCIES.items():
# 先尝试特定平台配置
if platform_id in type_config:
cfg = type_config[platform_id]
elif "default" in type_config:
cfg = type_config["default"]
else:
continue
# 记录 python 版本(优先使用有特殊要求的)
if cfg.get("python"):
python_version = cfg["python"]
# 收集依赖
for dep in cfg.get("dependencies", []):
all_deps.add(dep)
return python_version, list(all_deps)
# 单个类型的依赖
if key not in DEPENDENCIES:
return None, []
type_config = DEPENDENCIES[key]
if platform_id in type_config:
cfg = type_config[platform_id]
elif "default" in type_config:
cfg = type_config["default"]
else:
return None, []
return cfg.get("python"), cfg.get("dependencies", [])
def generate_uv_args(
dependencies: list,
test_path: str,
pytest_args: list,
python_version: str = None,
):
"""
生成 uv run 命令参数列表(用于 subprocess.run
Args:
dependencies: 依赖包列表
test_path: 测试路径
pytest_args: 透传给 pytest 的参数
python_version: 需要的 python 版本None 表示不指定
Returns:
uv run 命令参数列表
"""
args = ["uv", "run"]
if python_version:
args.extend(["--python", python_version])
# 添加 pytest
args.extend(["--with", "pytest"])
# 添加其他依赖
for dep in dependencies:
args.extend(["--with", dep])
# 添加 pytest 命令
args.append("pytest")
# 添加测试路径
args.append(test_path)
# 添加透传的 pytest 参数
args.extend(pytest_args)
return args
def main():
"""主函数:解析参数并运行测试"""
# 解析命令行参数
parser = argparse.ArgumentParser(
description="自动根据测试类型加载依赖并运行 pytest",
usage="%(prog)s <test_type> [pytest_args...]",
)
parser.add_argument(
"test_type",
choices=list(_TEST_TYPES.keys()),
help="测试类型: " + ", ".join(_TEST_TYPES.keys()),
)
parser.add_argument(
"pytest_args",
nargs=argparse.REMAINDER,
help="透传给 pytest 的参数(如 -v, --cov 等)",
)
# 如果没有参数,显示帮助
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
# 特殊处理:如果第一个参数是帮助选项
if sys.argv[1] in ("-h", "--help"):
parser.print_help()
sys.exit(0)
# 使用 parse_known_args 来正确处理透传参数
# 因为 argparse.REMAINDER 会吃掉 --help我们手动处理
test_type = sys.argv[1]
pytest_args = sys.argv[2:]
# 验证 test_type
if test_type not in _TEST_TYPES:
print(f"错误: 未知的测试类型 '{test_type}'")
print(f"可用类型: {', '.join(_TEST_TYPES.keys())}")
sys.exit(1)
# 检测 uv 是否可用
uv_path = shutil.which("uv")
if not uv_path:
print("错误: 未找到 uv请先安装 uv")
sys.exit(1)
# 获取测试配置
test_config = _TEST_TYPES[test_type]
test_path = test_config["path"]
# 导入需要的模块
from core.advice_generator import get_platform
# 获取平台和依赖配置
platform_id = get_platform()
python_version, dependencies = get_dependencies_for_type(test_type, platform_id)
# 生成 uv 命令参数
uv_args = generate_uv_args(
dependencies=dependencies,
test_path=test_path,
pytest_args=pytest_args,
python_version=python_version,
)
# 设置环境变量
env = os.environ.copy()
env["PYTHONPATH"] = str(project_root)
# 执行测试
result = subprocess.run(uv_args, env=env, cwd=str(project_root))
sys.exit(result.returncode)
if __name__ == "__main__":
main()