"""环境与临时目录隔离(供需要 `wov_app.config` 路径常量的模块测试使用)。 规则要求测试可独立运行、不依赖全局 conftest,数据与产物目录就是测试代码 所在目录:本模块把"创建独立数据目录并把应用指向它"封装成显式调用的函数, 由各模块测试在自己的 fixture 里调用。 失败模式说明:`wov_app.config` 在**导入时**读取环境变量并锁定路径常量 (DATA_DIR / DB_PATH / STORAGE_DIR)。因此隔离必须在**首次导入** config 之前完成: - 模块级导入的测试文件(如 `from wov_app.config import STORAGE_DIR`)应在 文件顶部用 `configure_environment()`(不带 tmp_path 的进程级隔离)设置; - 测试函数内才导入 `wov_app` 的文件,可用 `isolated_data_dir(tmp_path)` 在导入前覆盖到每个用例自己的临时目录。 """ from __future__ import annotations import os import shutil import tempfile from pathlib import Path # 进程级临时根目录(进程退出即清理),供 `configure_environment()` 使用。 _PROCESS_ROOT: Path | None = None def process_data_root() -> Path: """返回(必要时创建)进程级测试数据根目录。 与全局 conftest 的区别:这里不使用 pytest 的 autouse fixture,也不在 导入时自动改环境变量;模块测试显式调用后才生效,因此单个模块目录 可以脱离其他测试独立运行。 """ global _PROCESS_ROOT if _PROCESS_ROOT is None: _PROCESS_ROOT = Path(tempfile.mkdtemp(prefix="vrsub-test-")) return _PROCESS_ROOT def configure_environment(data_root: Path | None = None) -> Path: """把应用的数据目录、数据库、存储与后台服务指向独立测试目录。 必须在导入 `wov_app.config`(或任何会导入它的模块)之前调用, 否则路径常量已按默认值锁定。返回实际使用的数据根目录。 """ root = data_root or process_data_root() os.environ["WOV_DATA_DIR"] = str(root / "data") os.environ["WOV_DB_PATH"] = str(root / "data" / "wov.db") os.environ["WOV_STORAGE_DIR"] = str(root / "storage") # 默认关闭自动种子与后台线程:测试显式控制执行时机,避免与断言竞态。 os.environ["WOV_AUTO_SEED"] = "0" os.environ["WOV_SCHEDULER_ENABLED"] = "0" os.environ["WOV_CLEANUP_ENABLED"] = "0" os.environ["WOV_BATCH_ENABLED"] = "0" return root def cleanup_data_root(root: Path) -> None: """清理测试数据根目录(忽略错误,进程退出或 fixture 收尾时调用)。""" shutil.rmtree(root, ignore_errors=True)