Skip to main content

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:

FolderPurpose
unit/Fast, isolated logic tests
integration/DB + API + Async tests
e2e/Full workflow scenarios
factories/Model and payload generators
utils/Reusable test helpers
conftest.pyGlobal fixtures