""" Pytest configuration and fixtures for testing. """ import pytest from fastapi.testclient import TestClient from sqlalchemy import create_engine, event from sqlalchemy.orm import sessionmaker, Session from sqlalchemy.pool import StaticPool from app import app from adapters.postgres.database import Base, get_db # Create test database SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" engine = create_engine( SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}, poolclass=StaticPool, ) TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) @pytest.fixture(scope="session", autouse=True) def setup_test_database(): """Create test database tables once for the entire test session.""" Base.metadata.create_all(bind=engine) yield Base.metadata.drop_all(bind=engine) @pytest.fixture(scope="function") def db_session() -> Session: """ Create a clean database session for each test. This fixture ensures complete database isolation between tests. """ connection = engine.connect() transaction = connection.begin() session = TestingSessionLocal(bind=connection) # Enable nested transactions session.begin_nested() @event.listens_for(session, "after_transaction_end") def restart_savepoint(session, transaction): if transaction.nested and not transaction._parent.nested: session.begin_nested() yield session session.close() transaction.rollback() connection.close() @pytest.fixture(scope="function") def clean_db(): """ Fixture that cleans the database before and after each test. Use this when you need a completely clean database state. """ # Clean before test session = TestingSessionLocal() try: # Delete all data from all tables for table in reversed(Base.metadata.sorted_tables): session.execute(table.delete()) session.commit() finally: session.close() yield # Clean after test session = TestingSessionLocal() try: for table in reversed(Base.metadata.sorted_tables): session.execute(table.delete()) session.commit() finally: session.close() def override_get_db(): """Override the get_db dependency for testing.""" try: db = TestingSessionLocal() yield db finally: db.close() # Override the database dependency app.dependency_overrides[get_db] = override_get_db @pytest.fixture(scope="module") def client(): """Create a test client for the FastAPI application.""" return TestClient(app) @pytest.fixture(scope="function") def test_client(clean_db): """ Create a test client with a clean database for each test. Use this fixture when you need database isolation. """ return TestClient(app)