"""Shared fixtures. Unit tests must stay hermetic: no database, no Redis, no network. Anything that needs real infrastructure belongs in ``tests/integration`` behind the ``integration`` marker. """ from __future__ import annotations import shutil from pathlib import Path import pytest # 单测里给出确定的配置,避免开发者本机 .env 的取值渗进断言里。 # 必须在导入任何读取 Settings 的模块之前生效,故用 autouse=True + session 作用域。 _TEST_ENV = { "APP_ENV": "local", "LOG_JSON": "false", "JWT_SECRET": "unit-test-secret-not-used-outside-tests-0123456789", "DEEPSEEK_API_KEY": "unit-test-placeholder-never-called", "LLM_DAILY_BUDGET_ENABLED": "true", } @pytest.fixture(scope="session", autouse=True) def _isolate_settings() -> None: import os for key, value in _TEST_ENV.items(): os.environ.setdefault(key, value) @pytest.fixture(scope="session") def repo_root() -> Path: return Path(__file__).resolve().parent.parent @pytest.fixture def prompts_dir(repo_root: Path, tmp_path: Path) -> Path: """A writable copy of the shipped prompts, plus a second version of agent_chat. Copying rather than pointing at ``prompts/`` keeps two properties that matter: tests can add versions without dirtying the repo, and the shipped prompts are still the ones under test (a hand-written fixture would drift from production). """ target = tmp_path / "prompts" shutil.copytree(repo_root / "prompts", target) v2 = target / "agent_chat" / "v2.txt" v2.write_text( "[system]\n" "你是「美搭」的穿搭顾问助手(v2 试验版本,仅用于测试版本切换)。\n" "规则与 v1 相同,此处仅改动固定前缀以便断言两个版本不同。\n" "\n" "[user]\n" "{user_input}\n", encoding="utf-8", ) return target