Database rollback fixtures in PyTest - Build an Automation Script
Start learning this pattern below
Jump into concepts and practice - no test required
import pytest from sqlalchemy import create_engine, text from sqlalchemy.orm import sessionmaker # Setup database engine and sessionmaker engine = create_engine('sqlite:///test.db', echo=False, future=True) Session = sessionmaker(bind=engine, future=True) @pytest.fixture(scope='function') def db_session(): session = Session() connection = session.connection() trans = connection.begin() # start transaction try: yield session finally: trans.rollback() # rollback after test session.close() def test_insert_user(db_session): # Insert user db_session.execute(text("INSERT INTO users (id, name) VALUES (1, 'Test User')")) db_session.commit() # commit inside session to persist in transaction # Query to verify insertion result = db_session.execute(text("SELECT name FROM users WHERE id=1")).fetchone() assert result is not None assert result[0] == 'Test User' def test_user_not_persisted(): # New session to check if user exists after rollback with Session() as session: result = session.execute(text("SELECT name FROM users WHERE id=1")).fetchone() assert result is None
The db_session fixture creates a new database session and starts a transaction before each test. It yields the session to the test function. After the test finishes, the fixture rolls back the transaction to undo any changes made during the test, ensuring the database stays clean.
In test_insert_user, we insert a user and commit inside the transaction so the data is visible within the test. We then query to confirm the user exists. Because the fixture rolls back after the test, the inserted user is not saved permanently.
The test_user_not_persisted test opens a new session and verifies that the user inserted in the previous test does not exist, confirming the rollback worked.
This approach keeps tests isolated and prevents side effects between tests.
Now add data-driven testing with 3 different user names to insert and verify rollback for each
Practice
Solution
Step 1: Understand the role of rollback fixtures
Rollback fixtures undo any changes made to the database during a test to keep tests isolated.Step 2: Compare options with rollback purpose
Only To undo database changes after each test to keep tests independent describes undoing changes after tests, which matches rollback behavior.Final Answer:
To undo database changes after each test to keep tests independent -> Option DQuick Check:
Rollback fixture purpose = undo changes [OK]
- Confusing rollback with speeding up queries
- Thinking rollback creates tables
- Assuming rollback saves data permanently
Solution
Step 1: Understand yield usage in fixtures
Yield separates setup (before yield) and teardown (after yield) in pytest fixtures.Step 2: Identify correct order for rollback
Setup happens before yield, rollback (cleanup) after yield. @pytest.fixture def db_fixture(): setup_db() yield rollback_db() follows this order.Final Answer:
@pytest.fixture\ndef db_fixture():\n setup_db()\n yield\n rollback_db() -> Option AQuick Check:
Setup before yield, rollback after yield [OK]
- Placing rollback before yield
- Calling setup after yield
- Not using yield at all
@pytest.fixture
def db_fixture():
connect_db()
yield
rollback_db()
def test_add_record(db_fixture):
add_record_to_db('test')
assert count_records() == 1
Solution
Step 1: Understand fixture behavior with yield
The fixture sets up connection, yields control to test, then rolls back changes after test finishes.Step 2: Analyze test effect on database
The test adds one record and asserts count is 1 during test, but rollback removes it after test.Final Answer:
0 -> Option AQuick Check:
Rollback clears changes after test [OK]
- Assuming record stays after test
- Confusing assert inside test with final state
- Thinking rollback happens before test
@pytest.fixture
def db_fixture():
setup_db()
rollback_db()
yield
What is the main problem?Solution
Step 1: Check order of setup, yield, and rollback
Rollback must happen after yield to undo changes after test runs.Step 2: Identify error in fixture code
Rollback is called before yield, so changes are undone before test, not after.Final Answer:
Rollback is called before yield, so changes are undone before test runs -> Option CQuick Check:
Rollback after yield for cleanup [OK]
- Calling rollback before yield
- Forgetting yield entirely
- Calling setup after yield
Solution
Step 1: Understand transaction lifecycle in fixtures
Start transaction before yield to begin test with transaction active.Step 2: Rollback after yield to undo changes after test
Rollback must happen after yield to clean up changes made during test.Final Answer:
@pytest.fixture\ndef db_transaction():\n start_transaction()\n yield\n rollback_transaction() -> Option BQuick Check:
Start before yield, rollback after yield [OK]
- Calling rollback before yield
- Calling start_transaction after yield
- Not using yield to separate setup and cleanup
