Complete worked example
python
import sqlite3
import pytest
def add_name(db, value):
db.execute("INSERT INTO names(value) VALUES (?)", (value,))
@pytest.fixture
def db():
connection = sqlite3.connect(":memory:")
connection.execute("CREATE TABLE names(value TEXT NOT NULL)")
try:
yield connection
finally:
connection.close()
def test_inserted_value(db):
add_name(db, "Ada")
assert db.execute("SELECT value FROM names").fetchall() == [("Ada",)]
def test_failed_transaction_rolls_back(db):
with pytest.raises(RuntimeError, match="cancel"):
with db:
add_name(db, "temporary")
raise RuntimeError("cancel")
assert db.execute("SELECT COUNT(*) FROM names").fetchone()[0] == 0- Reasoning
- The fixture creates a connection, initializes one table, yields it and closes it in finally. The helper inserts a parameterized value. A normal insertion is checked through an independent SELECT query. A second test raises inside the connection context and confirms the transaction rolled back. The context manager manages commit or rollback for a transaction; it does not itself replace the need to close the connection. Keeping close in the fixture makes that ownership explicit. Bound parameters prevent values from becoming SQL syntax and also preserve quotes correctly.