From 98d3295ef3bbb5987c67d0e5d6371be8ebadf262 Mon Sep 17 00:00:00 2001 From: GlennIgen Date: Sat, 11 Jul 2026 04:01:28 +0200 Subject: [PATCH] tests: function-scoped engine + frisk session per request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- backend/tests/conftest.py | 84 ++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index b2e633e..6ebe6e2 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -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_asyncio @@ -21,72 +26,61 @@ DATABASE_URL = os.getenv( ) -@pytest_asyncio.fixture(scope="session") +@pytest_asyncio.fixture(autouse=True) 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) async with e.begin() as conn: await conn.run_sync(Base.metadata.drop_all) await conn.run_sync(Base.metadata.create_all) yield e - async with e.begin() as conn: - await conn.run_sync(Base.metadata.drop_all) await e.dispose() @pytest_asyncio.fixture -async def session(engine): - """Per-test database session. - - Data commited her er synlig for appens egen session via HTTP client. - Renses automatisk af _clean_db efter hver test. - """ +async def client(engine): + """HTTP client — appen får en frisk session på testens engine per request.""" 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) -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().""" + app.dependency_overrides[get_db] = override_get_db transport = ASGITransport(app=app) async with AsyncClient(transport=transport, base_url="http://test") as ac: yield ac + app.dependency_overrides.clear() @pytest_asyncio.fixture -async def admin_user(session): - """Insert admin user into test DB (ryddes af _clean_db).""" - u = User( - username="admin", - password_hash=hash_password("admin123"), - role="admin", - ) - session.add(u) - await session.commit() - return u +async def admin_user(engine): + """Insert admin user — frisk session, committer, lukker.""" + maker = async_sessionmaker(bind=engine, expire_on_commit=False) + async with maker() as s: + u = User( + username="admin", + password_hash=hash_password("admin123"), + role="admin", + ) + s.add(u) + await s.commit() + return u @pytest_asyncio.fixture -async def normal_user(session): - """Insert normal user into test DB (ryddes af _clean_db).""" - u = User( - username="testuser", - password_hash=hash_password("test123"), - role="user", - ) - session.add(u) - await session.commit() - return u +async def normal_user(engine): + """Insert normal user — frisk session, committer, lukker.""" + maker = async_sessionmaker(bind=engine, expire_on_commit=False) + async with maker() as s: + u = User( + username="testuser", + password_hash=hash_password("test123"), + role="user", + ) + s.add(u) + await s.commit() + return u @pytest_asyncio.fixture