feat(01-02): add async db_session and async_client fixtures to conftest.py

- Add @pytest_asyncio.fixture db_session: in-memory SQLite via aiosqlite,
  expire_on_commit=False, skips gracefully (ImportError) before Plan 03
- Add @pytest_asyncio.fixture async_client: httpx.AsyncClient with
  ASGITransport, overrides deps.db.get_db, skips before Plan 03
- Retain all legacy sync fixtures (isolated_data_dir, client, sample_txt,
  sample_pdf) unchanged for backward compatibility through Plan 04
This commit is contained in:
curo1305
2026-05-22 09:05:36 +02:00
parent f9b8a0d1ca
commit 1f675fcf1a
+62
View File
@@ -1,15 +1,25 @@
"""
pytest configuration: isolate each test with a temporary data directory.
Async fixtures (db_session, async_client) are added for Phase 1 — sync fixtures remain until Plan 05 cuts over.
"""
from __future__ import annotations
import os
import json
import pytest
import pytest_asyncio
import tempfile
import shutil
from pathlib import Path
from fastapi.testclient import TestClient
from httpx import AsyncClient, ASGITransport
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy.pool import StaticPool
# ── Sync fixtures (legacy — retained until Plan 05 cuts over) ──────────────────
@pytest.fixture(autouse=True)
def isolated_data_dir(monkeypatch, tmp_path):
"""Each test gets its own clean data directory."""
@@ -68,3 +78,55 @@ def sample_pdf(tmp_path):
doc.save(str(pdf_path))
doc.close()
return pdf_path
# ── Async fixtures (Phase 1 additions — Plan 03+ tests use these) ──────────────
@pytest_asyncio.fixture
async def db_session():
"""In-memory async SQLite session for unit tests.
Tries to import db.models.Base (available after Plan 03). If the module
does not yet exist the fixture skips the test gracefully so the suite
stays green during Wave 1.
"""
engine = create_async_engine(
"sqlite+aiosqlite:///:memory:",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
try:
from db.models import Base
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
except ImportError:
await engine.dispose()
pytest.skip("db.models not yet implemented — plan 03")
AsyncTestSession = async_sessionmaker(engine, expire_on_commit=False)
async with AsyncTestSession() as session:
yield session
await engine.dispose()
@pytest_asyncio.fixture
async def async_client(db_session):
"""Async HTTP test client with DB dependency overridden.
Tries to import deps.db.get_db (available after Plan 03). If the module
does not yet exist the fixture skips the test gracefully.
"""
try:
from deps.db import get_db
from main import app
except ImportError as exc:
pytest.skip(f"deps.db.get_db not yet implemented — plan 03: {exc}")
app.dependency_overrides[get_db] = lambda: db_session
async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as c:
yield c
app.dependency_overrides.clear()