The same per-test sqlite-engine setup was duplicated across 14 test files (~30 lines each). Consolidated into a single async fixture `db_factory` in tests/conftest.py; tests now take db_factory as a parameter and use `async with db_factory() as session` directly. No behaviour change — same function-scope, same in-memory schema created via Base.metadata.create_all, same app.db._engine / _session_factory rebinding so module-level helpers see the test engine. Just ~420 lines of boilerplate removed.
56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
"""Pytest config — no DB / no network. Tests target pure functions only.
|
|
|
|
Heavy runtime deps (fastapi, httpx, sqlalchemy, pydantic-settings, tenacity)
|
|
are installed inside the container but not necessarily on the host. Tests
|
|
that need them use pytest.importorskip; the full suite runs via
|
|
`docker compose run --rm app pytest tests/`."""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
# Sentinel env so importing app.config doesn't try to read a missing .env.
|
|
os.environ.setdefault("DATABASE_URL", "sqlite+aiosqlite:///:memory:")
|
|
os.environ.setdefault("CASSANDRA_MOCK", "1")
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
async def db_factory(tmp_path):
|
|
"""Per-test sqlite engine + async session factory.
|
|
|
|
Creates a fresh sqlite database file under ``tmp_path``, applies
|
|
``Base.metadata.create_all``, and rebinds ``app.db._engine`` /
|
|
``app.db._session_factory`` so module-level helpers (which look
|
|
these up at call time) see the test engine.
|
|
|
|
Yields the ``async_sessionmaker``. Tests use it like:
|
|
|
|
async def test_foo(db_factory):
|
|
async with db_factory() as session:
|
|
...
|
|
"""
|
|
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
|
|
|
from app import db as db_mod
|
|
from app.db import Base
|
|
import app.models # noqa: F401 — registers models on Base.metadata
|
|
|
|
engine = create_async_engine(f"sqlite+aiosqlite:///{tmp_path}/test.db")
|
|
factory = async_sessionmaker(engine, expire_on_commit=False)
|
|
db_mod._engine = engine
|
|
db_mod._session_factory = factory
|
|
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
|
|
yield factory
|
|
|
|
await engine.dispose()
|