1- import os
2- import tempfile
31from pathlib import Path
42
53import pytest
@@ -28,25 +26,26 @@ def data_folder_path():
2826 return Path (__file__ ).parent .parent / "data"
2927
3028
31- @pytest .fixture (name = "session" )
32- def session_fixture (request , monkeypatch ) -> Session :
33- """Create a new database session for a test."""
29+ @pytest .fixture (scope = "session" )
30+ def db_engine (request , tmp_path_factory , session_mocker ):
31+ """
32+ Create a session-scoped database engine.
33+ Database is created once and migrations run once for all tests.
34+ """
3435 # TODO: Use an in-memory SQLite database for faster tests if possible.
3536 # https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/#memory-database
3637
3738 db_type = request .config .getoption ("--db" )
38-
3939 if db_type == "postgres" :
4040 db_url = "postgresql://develop:develop_secret@localhost:5432/develop"
41- path = None
4241 else :
4342 # Create a temporary database file for SQLite
44- fd , path = tempfile . mkstemp ( suffix = ". db" )
45- os . close ( fd )
46- db_url = f"sqlite:///{ path } "
43+ temp_dir = tmp_path_factory . mktemp ( " db" )
44+ db_path = temp_dir / "test.db"
45+ db_url = f"sqlite:///{ db_path } "
4746
4847 # Use monkeypatch to set DATABASE_URL environment variable
49- monkeypatch . setattr ("config.settings.DATABASE_URL" , db_url )
48+ session_mocker . patch ("config.settings.DATABASE_URL" , db_url )
5049
5150 # Get path to alembic.ini
5251 src_dir = Path (__file__ ).parents [1 ] / "src"
@@ -61,12 +60,22 @@ def session_fixture(request, monkeypatch) -> Session:
6160 # TODO: Alternatively, you can create tables directly without migrations for simpler setups.
6261 # create_db_and_tables(engine)
6362
64- # Ensure that changes made during tests do not persist and affect other tests using a nested transaction
65- # This is needed for PostgreSQL since the SQLite is erased after each test by deleting the temp file
66- connection = engine .connect ()
63+ yield engine
64+
65+ # Clean up at the end of the test session
66+ engine .dispose ()
67+
68+
69+ @pytest .fixture (name = "session" )
70+ def session_fixture (db_engine ) -> Session :
71+ """
72+ Create a new database session for a test, wrapped in a transaction that is rolled back after the test.
73+ """
74+
75+ connection = db_engine .connect ()
6776 transaction = connection .begin ()
6877 session = Session (bind = connection )
69-
78+ # Ensure that changes made during tests do not persist and affect other tests using a nested transaction
7079 nested = connection .begin_nested ()
7180
7281 @sa .event .listens_for (session , "after_transaction_end" )
@@ -77,15 +86,11 @@ def end_savepoint(session, transaction):
7786
7887 yield session
7988
89+ # Rollback the transaction (this undoes all changes made during the test)
8090 session .close ()
8191 transaction .rollback ()
8292 connection .close ()
8393
84- # Clean up
85- engine .dispose ()
86- if path :
87- os .unlink (path )
88-
8994
9095@pytest .fixture (name = "client_with_db" )
9196def client_fixture (session : Session ):
0 commit comments