ShiErFeng/shierfeng-fastapi-backend/tests/cli/tui/adapters/conftest.py
2026-07-24 09:43:10 +08:00

88 lines
2.3 KiB
Python

import asyncio
import importlib
import sys
from collections.abc import Callable
from pathlib import Path
from types import ModuleType
import pytest
BACKEND_DIR = Path(__file__).resolve().parents[4]
sys.path.insert(0, str(BACKEND_DIR))
def _load_adapter_module(module_name: str) -> ModuleType:
sys.modules.pop(module_name, None)
sys.modules.pop('cli', None)
return importlib.import_module(module_name)
@pytest.fixture
def app_adapter() -> ModuleType:
return _load_adapter_module('cli.tui.adapters.app')
@pytest.fixture
def cache_adapter() -> ModuleType:
return _load_adapter_module('cli.tui.adapters.cache')
@pytest.fixture
def crypto_adapter() -> ModuleType:
return _load_adapter_module('cli.tui.adapters.crypto')
@pytest.fixture
def database_adapter() -> ModuleType:
return _load_adapter_module('cli.tui.adapters.database')
@pytest.fixture
def jobs_adapter() -> ModuleType:
return _load_adapter_module('cli.tui.adapters.jobs')
@pytest.fixture
def gen_adapter() -> ModuleType:
return _load_adapter_module('cli.tui.adapters.gen')
@pytest.fixture
def configs_adapter() -> ModuleType:
return _load_adapter_module('cli.tui.adapters.configs')
@pytest.fixture
def ops_adapter() -> ModuleType:
return _load_adapter_module('cli.tui.adapters.ops')
@pytest.fixture
def health_adapter() -> ModuleType:
return _load_adapter_module('cli.tui.adapters.health')
@pytest.fixture
def load_adapter_module() -> Callable[[str], ModuleType]:
return _load_adapter_module
@pytest.fixture(autouse=True)
def dispose_async_db_engine_after_test() -> None:
"""
在每个 TUI adapter 测试结束后尝试释放全局异步数据库连接池。
这些适配器测试会按需导入运行时模块;若其中某些路径触发真实数据库访问,
模块级 `async_engine` 可能在测试进程结束前仍持有连接,从而在 GC 阶段产生
SQLAlchemy 未归还连接告警。这里统一在测试后主动 `dispose()`,将清理职责收口
到测试夹具而非业务代码。
:return: None
"""
yield
database_module = sys.modules.get('config.database')
async_engine = getattr(database_module, 'async_engine', None) if database_module is not None else None
if async_engine is not None:
asyncio.run(async_engine.dispose())