Test folder structure template
- Unit tests
- Integration tests
- Async tests
- DB-mocked tests
- JWT auth tests
- Fixtures
- Factories
- Utilities
Recommended Test Folder Structure
tests/
│
├── __init__.py
│
├── conftest.py # Global pytest fixtures (DB, clients, settings)
│
├── factories/ # Data builders / model factories
│ ├── __init__.py
│ └── user_factory.py
│
├── utils/ # Shared testing utilities
│ ├── __init__.py
│ └── jwt_helpers.py
│
├── unit/ # Pure unit tests (no DB, no FastAPI)
│ ├── __init__.py
│ └── test_helpers.py
│
├── integration/ # API + DB tests, Async tests
│ ├── __init__.py
│ ├── test_users.py
│ └── test_auth.py
│
└── e2e/ # End-to-end tests (simulate full behavior)
├── __init__.py
└── test_full_flow.py
What Each Folder Contains
✔ tests/conftest.py
Global fixtures for:
- Async test client
- Mocked async SQLAlchemy database
- Dependency overrides
- JWT token helper fixture
Example:
import pytest
from httpx import AsyncClient
from app.main import app
@pytest.fixture
async def client():
async with AsyncClient(app=app, base_url="http://test") as c:
yield c
factories/
Used to create reusable model objects (factory pattern).
Example — user_factory.py:
def user_payload(username="alice", job="Engineer"):
return {"username": username, "job": job}
utils/
Helper functions for repetitive tasks.
Example — jwt_helpers.py:
from app.auth import create_access_token
def get_token(user="test_user"):
return create_access_token({"sub": user})
unit/
Pure Python tests, no FastAPI, no DB.
Example — test_helpers.py:
from app.utils.math import add
def test_add():
assert add(2, 3) == 5
integration/
Tests FastAPI endpoints, async DB, JWT, etc.
Example — test_users.py:
import pytest
@pytest.mark.asyncio
async def test_create_user(client):
response = await client.post("/users", params={"username": "bob", "job": "Manager"})
assert response.status_code == 200
e2e/
Simulate full workflows across endpoints.
Example — test_full_flow.py:
@pytest.mark.asyncio
async def test_user_full_flow(client):
# Create user
res = await client.post("/users", params={"username": "eva", "job": "Dev"})
assert res.status_code == 200
# Fetch user
res = await client.get("/users/eva")
assert res.json()["job"] == "Dev"
Summary
This test structure supports:
| Folder | Purpose |
|---|---|
unit/ | Fast, isolated logic tests |
integration/ | DB + API + Async tests |
e2e/ | Full workflow scenarios |
factories/ | Model and payload generators |
utils/ | Reusable test helpers |
conftest.py | Global fixtures |