Skip to content

bluefox_test_setup()

The main setup function that wires all test infrastructure together.


Signature

def bluefox_test_setup(
    base,                                          # SQLAlchemy DeclarativeBase
    binds: dict[str, str] | None = None,           # {"analytics": "analytics.models:Base"}
    src_root: str = "src",                         # where to discover tests/factories.py
    postgres_image: str = "postgres:16-alpine",
    redis_image: str = "redis:7-alpine",
    app_factory: str | None = "app.main:create_app",
    session_dependency: str | None = "app.deps:get_session",
) -> dict[str, Any]:

Returns a dict of pytest fixtures. Inject via globals().update(...) in your root conftest.py.


Parameters

Parameter Type Default Description
base DeclarativeBase required Your SQLAlchemy base class. Used for create_all().
binds dict[str, str] \| None None Named additional databases. Keys become fixture names (db_<key>). Values are dotted paths to bind base classes.
src_root str "src" Root directory for factory auto-discovery.
postgres_image str "postgres:16-alpine" Docker image for the Postgres container.
redis_image str "redis:7-alpine" Docker image for the Redis container.
app_factory str \| None "app.main:create_app" Dotted path to your FastAPI app factory. Set to None to skip app/client fixtures.
session_dependency str \| None "app.deps:get_session" Dotted path to the FastAPI dependency that yields a session. Used for dependency override.

Fixtures provided

Fixture Scope Description
infra session Starts Postgres + Redis containers, yields URLs
safe_env session, autouse Overwrites env vars with container URLs, runs safety checks
engine session Async engine for main DB, runs create_all()
db function SAVEPOINT-wrapped async session, binds factories
app function FastAPI app with test session injected via dependency override
client function httpx AsyncClient wired to the app via ASGI transport
bind_engines session Per-bind engines (only when binds is provided)
db_<name> function Per-bind SAVEPOINT sessions (one for each key in binds)
create_* function One per factory discovered in tests/factories.py files

How app wiring works

The package imports your app factory and session dependency using the dotted paths:

# This is what happens internally — you don't write this
from app.main import create_app
from app.deps import get_session

application = create_app()

async def _override_session():
    yield test_session

application.dependency_overrides[get_session] = _override_session

If your app doesn't follow this pattern, set app_factory=None and define your own app and client fixtures. See the custom app wiring guide.


Examples

Minimal setup

conftest.py
from bluefox_test import bluefox_test_setup
from app.models import Base

globals().update(bluefox_test_setup(base=Base))

With multiple databases

conftest.py
from bluefox_test import bluefox_test_setup
from app.models import Base

globals().update(
    bluefox_test_setup(
        base=Base,
        binds={
            "analytics": "analytics.models:AnalyticsBase",
        },
    )
)

Without app fixtures

conftest.py
from bluefox_test import bluefox_test_setup
from app.models import Base

globals().update(bluefox_test_setup(base=Base, app_factory=None))

This gives you db, engine, and factory fixtures, but no app or client.