Skip to content

Commit 4281a20

Browse files
committed
test: prove db_session rollback with one self-contained test
1 parent 2a6eea9 commit 4281a20

2 files changed

Lines changed: 26 additions & 12 deletions

File tree

‎tests/conftest.py‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import contextlib
12
import typing
23

34
import litestar
@@ -38,8 +39,8 @@ async def di_container(app: litestar.Litestar) -> typing.AsyncIterator[modern_di
3839
await container.close_async()
3940

4041

41-
@pytest.fixture
42-
async def db_session(di_container: modern_di.Container) -> typing.AsyncIterator[AsyncSession]:
42+
@contextlib.asynccontextmanager
43+
async def rolled_back_db_session(di_container: modern_di.Container) -> typing.AsyncIterator[AsyncSession]:
4344
engine = create_database_engine()
4445
connection = await engine.connect()
4546
transaction = await connection.begin()
@@ -53,3 +54,9 @@ async def db_session(di_container: modern_di.Container) -> typing.AsyncIterator[
5354
await connection.close()
5455
await engine.dispose()
5556
di_container.reset_override(ioc.Database.database_engine)
57+
58+
59+
@pytest.fixture
60+
async def db_session(di_container: modern_di.Container) -> typing.AsyncIterator[AsyncSession]:
61+
async with rolled_back_db_session(di_container) as session:
62+
yield session

‎tests/test_main.py‎

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from app.database.tables import UsersTable
1212
from app.exceptions import PermissionDeniedError
1313
from app.settings import settings
14+
from tests.conftest import rolled_back_db_session
1415
from tests.factories import UserFactory
1516

1617

@@ -52,18 +53,24 @@ async def test_create_database_engine_reads_settings_and_can_be_disposed() -> No
5253
await close_database_engine(engine)
5354

5455

55-
async def test_db_session_insert_is_visible_within_test(db_session: AsyncSession) -> None:
56-
user = UserFactory.build()
57-
db_session.add(user)
58-
await db_session.commit()
59-
60-
result = await db_session.scalars(sa.select(UsersTable))
61-
assert len(result.all()) == 1
56+
async def test_db_session_teardown_rolls_back_committed_writes(di_container: modern_di.Container) -> None:
57+
"""INVARIANT: a commit inside a test only releases a savepoint, and teardown discards it.
6258
59+
The row is read back from an independent connection after teardown, so the check holds whatever runs before it.
60+
"""
61+
user = UserFactory.build()
62+
async with rolled_back_db_session(di_container) as session:
63+
session.add(user)
64+
await session.commit()
65+
assert (await session.scalars(sa.select(UsersTable).where(UsersTable.id == user.id))).one() is user
6366

64-
async def test_db_session_rolls_back_between_tests(db_session: AsyncSession) -> None:
65-
result = await db_session.scalars(sa.select(UsersTable))
66-
assert result.all() == []
67+
engine = create_database_engine()
68+
try:
69+
async with engine.connect() as connection:
70+
result = await connection.scalars(sa.select(UsersTable.id).where(UsersTable.id == user.id))
71+
assert result.all() == []
72+
finally:
73+
await engine.dispose()
6774

6875

6976
async def test_di_resolved_session_shares_the_overridden_connection(

0 commit comments

Comments
 (0)