# -*- coding: utf-8 -*- """测试命令仓库:集中维护 run_tests.py 的常用组合,并支持一键执行。 参数键说明(可在 PRESETS 中任意叠加): 1. suite 类型:列表;值:["online"], ["offline"], ["integration"] 等。 含义:引用 run_tests 内置测试套件。online=在线模式;offline=离线模式;integration=数据库集成测试。 用法:["online","offline"] 表示一次执行两套;["integration"] 仅跑数据库相关用例。 2. tests 类型:列表;示例:["tests/unit/test_config.py"]。 含义:自定义的 pytest 目标路径,适合补充临时/个别测试。 3. mode 类型:字符串;取值:"ONLINE" 或 "OFFLINE"。 含义:覆盖 TEST_MODE;ONLINE 走 API 全流程,OFFLINE 读取 JSON 归档执行 Transform + Load。 4. db_dsn 类型:字符串;示例:postgresql://user:pwd@host:5432/testdb。 含义:设置 TEST_DB_DSN,使用真实 PostgreSQL 连接;不设置则使用伪 DB(仅记录操作,不落库)。 5. json_archive / json_temp 类型:字符串;示例:"tests/testdata_json"、"C:/tmp/json"。 含义:离线模式所需的归档输入目录 / 临时输出目录。未设置时沿用 .env 或默认配置。 6. keyword 类型:字符串;示例:"ORDERS"。 含义:等价 pytest -k,可筛选测试名/节点,只运行包含该关键字的用例。 7. pytest_args 类型:字符串;示例:"-vv --maxfail=1"。 含义:追加 pytest 命令行参数,用于控制日志、失败策略等。 8. env 类型:列表;示例:["STORE_ID=123","API_TOKEN=xxx"]。 含义:额外的环境变量,在调用 run_tests 前注入到 os.environ。 9. preset_meta 类型:字符串;仅用于描述场景,不会传给 run_tests(纯注释)。 使用方式: - 直接 F5 或 `python scripts/test_presets.py`:读取 AUTO_RUN_PRESETS 的预置并顺序执行。 - `python scripts/test_presets.py --preset offline_realdb`:临时指定要运行的组合。 - `python scripts/test_presets.py --list`:查看参数说明及所有预置详情。 """ from __future__ import annotations import argparse import os import subprocess import sys from typing import List RUN_TESTS_SCRIPT = os.path.join(os.path.dirname(__file__), "run_tests.py") # 默认自动运行的预置(可自定义顺序) AUTO_RUN_PRESETS = ["offline_realdb"] PRESETS = { "online_orders": { "suite": ["online"], "mode": "ONLINE", "keyword": "ORDERS", "pytest_args": "-vv", "preset_meta": "在线模式,仅跑订单任务并输出详细日志", }, "offline_realdb": { "suite": ["offline"], "mode": "OFFLINE", "db_dsn": "postgresql://local-Python:Neo-local-1991125@100.64.0.4:5432/LLZQ-test", "json_archive": "tests/testdata_json", "keyword": "ORDERS", "preset_meta": "离线模式 + 真实测试库,用预置 JSON 回放并写入测试库", }, } def print_parameter_help() -> None: print("=== 参数键说明 ===") print("suite : 预置套件列表,如 ['online','offline']") print("tests : 自定义 pytest 路径列表") print("mode : TEST_MODE(ONLINE/ OFFLINE)") print("db_dsn : TEST_DB_DSN,连接真实 PostgreSQL") print("json_archive : TEST_JSON_ARCHIVE_DIR,离线模式输入目录") print("json_temp : TEST_JSON_TEMP_DIR,离线模式临时目录") print("keyword : pytest -k 过滤关键字") print("pytest_args : 额外 pytest 参数(字符串)") print("env : 附加环境变量,例如 ['KEY=VALUE']") print("preset_meta : 仅用于注释说明") print() def print_presets() -> None: if not PRESETS: print("当前未定义任何预置,请在 PRESETS 中添加。") return for idx, (name, payload) in enumerate(PRESETS.items(), start=1): comment = payload.get("preset_meta", "") print(f"{idx}. {name}") if comment: print(f" 说明: {comment}") for key, value in payload.items(): if key == "preset_meta": continue print(f" {key}: {value}") print() def resolve_targets(requested: List[str] | None) -> List[str]: if not PRESETS: raise SystemExit("Pre-sets 为空,请先在 PRESETS 中定义测试组合。") def valid(names: List[str]) -> List[str]: return [name for name in names if name in PRESETS] if requested: candidates = valid(requested) missing = [name for name in requested if name not in PRESETS] if missing: print(f"警告:忽略未定义的预置 {missing}") if candidates: return candidates auto = valid(AUTO_RUN_PRESETS) if auto: return auto # 兜底:全部预置 return list(PRESETS.keys()) def run_presets(preset_names: List[str], dry_run: bool) -> None: for name in preset_names: cmd = [sys.executable, RUN_TESTS_SCRIPT, "--preset", name] printable = " ".join(cmd) if dry_run: print(f"[Dry-Run] {printable}") else: print(f"\n>>> 执行: {printable}") subprocess.run(cmd, check=False) def main() -> None: parser = argparse.ArgumentParser(description="测试预置仓库(集中配置即可批量触发 run_tests)") parser.add_argument("--preset", choices=sorted(PRESETS.keys()), nargs="+", help="指定要运行的预置命令") parser.add_argument("--list", action="store_true", help="仅列出参数说明与所有预置") parser.add_argument("--dry-run", action="store_true", help="仅打印命令,不执行 pytest") args = parser.parse_args() if args.list: print_parameter_help() print_presets() return targets = resolve_targets(args.preset) run_presets(targets, dry_run=args.dry_run) if __name__ == "__main__": main()