tests: function-scoped engine + frisk session per request
CI/CD / test (push) Failing after 1m34s
CI/CD / build (push) Has been skipped

Hver test får sin egen engine (function-scoped) med friske
tabeller (drop_all + create_all). Appen får sin egen session
per request via dependency override — ingen deling af sessions.

admin_user/normal_user opretter data via egen session og
lukker den. client bruger async_sessionmaker i override_get_db.

Ingen _clean_db fixture, ingen outer transaction, ingen
SAVEPOINT — hver test starter blankt og engine.dispose()
rydder op.
This commit is contained in:
2026-07-11 04:01:28 +02:00
parent 1c23e45261
commit 98d3295ef3
+39 -45
View File
@@ -1,4 +1,9 @@
"""Test fixtures — async database and HTTP client.""" """Test fixtures — async database and HTTP client.
Hver test får sin egen engine (function-scoped) med friske tabeller.
Appen får sin egen session per request via dependency override.
Ingen delte sessions — ingen "another operation is in progress".
"""
import pytest import pytest
import pytest_asyncio import pytest_asyncio
@@ -21,72 +26,61 @@ DATABASE_URL = os.getenv(
) )
@pytest_asyncio.fixture(scope="session") @pytest_asyncio.fixture(autouse=True)
async def engine(): async def engine():
"""Create a fresh database for testing.""" """Frisk engine per test — skaber tabeller, smider væk bagefter."""
e = create_async_engine(DATABASE_URL, echo=False) e = create_async_engine(DATABASE_URL, echo=False)
async with e.begin() as conn: async with e.begin() as conn:
await conn.run_sync(Base.metadata.drop_all) await conn.run_sync(Base.metadata.drop_all)
await conn.run_sync(Base.metadata.create_all) await conn.run_sync(Base.metadata.create_all)
yield e yield e
async with e.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
await e.dispose() await e.dispose()
@pytest_asyncio.fixture @pytest_asyncio.fixture
async def session(engine): async def client(engine):
"""Per-test database session. """HTTP client — appen får en frisk session på testens engine per request."""
Data commited her er synlig for appens egen session via HTTP client.
Renses automatisk af _clean_db efter hver test.
"""
maker = async_sessionmaker(bind=engine, expire_on_commit=False) maker = async_sessionmaker(bind=engine, expire_on_commit=False)
async with maker() as s:
yield s
async def override_get_db():
async with maker() as s:
yield s
@pytest_asyncio.fixture(autouse=True) app.dependency_overrides[get_db] = override_get_db
async def _clean_db(engine):
"""Slet alt data fra alle tabeller efter hver test."""
yield
async with engine.begin() as conn:
for table in reversed(Base.metadata.sorted_tables):
await conn.execute(table.delete())
@pytest_asyncio.fixture
async def client():
"""HTTP client — appen bruger sin egen DB session via get_db()."""
transport = ASGITransport(app=app) transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as ac: async with AsyncClient(transport=transport, base_url="http://test") as ac:
yield ac yield ac
app.dependency_overrides.clear()
@pytest_asyncio.fixture @pytest_asyncio.fixture
async def admin_user(session): async def admin_user(engine):
"""Insert admin user into test DB (ryddes af _clean_db).""" """Insert admin user — frisk session, committer, lukker."""
u = User( maker = async_sessionmaker(bind=engine, expire_on_commit=False)
username="admin", async with maker() as s:
password_hash=hash_password("admin123"), u = User(
role="admin", username="admin",
) password_hash=hash_password("admin123"),
session.add(u) role="admin",
await session.commit() )
return u s.add(u)
await s.commit()
return u
@pytest_asyncio.fixture @pytest_asyncio.fixture
async def normal_user(session): async def normal_user(engine):
"""Insert normal user into test DB (ryddes af _clean_db).""" """Insert normal user — frisk session, committer, lukker."""
u = User( maker = async_sessionmaker(bind=engine, expire_on_commit=False)
username="testuser", async with maker() as s:
password_hash=hash_password("test123"), u = User(
role="user", username="testuser",
) password_hash=hash_password("test123"),
session.add(u) role="user",
await session.commit() )
return u s.add(u)
await s.commit()
return u
@pytest_asyncio.fixture @pytest_asyncio.fixture