Testing¶
Test patterns and factories for HTTP API and Celery tasks.
Overview¶
The testing architecture provides:
- Test Factories — Per-test isolation with IoC override capability
- HTTP API Tests — Django-Ninja test client integration
- Celery Tests — In-process worker for task testing
- IoC Mocking — Dependency injection for test doubles
Test Stack¶
| Tool | Purpose |
|---|---|
| pytest | Test runner |
| pytest-django | Django integration |
| ninja.testing | HTTP API client |
| celery.contrib.testing | Celery worker testing |
| punq | IoC container |
Topics¶
-
Test Factories
Creating test clients with IoC container isolation.
-
HTTP API Tests
Testing REST endpoints with test client.
-
Celery Task Tests
Testing background tasks with in-process worker.
-
Mocking IoC Dependencies
Overriding dependencies for test isolation.
Running Tests¶
This runs pytest with 80% coverage requirement.
Test Configuration¶
Tests use .env.test for configuration:
# .env.test
DJANGO_SECRET_KEY=test-secret
JWT_SECRET_KEY=test-jwt-secret
DATABASE_URL=postgres://postgres:test@localhost:5432/test_db
REDIS_URL=redis://localhost:6379/1
Test Structure¶
tests/
├── conftest.py # Root pytest configuration
└── integration/
├── conftest.py # Integration fixtures
├── factories.py # Test factories
└── http/
└── test_user.py # HTTP endpoint tests
Quick Example¶
import pytest
from ninja.testing import TestClient
from tests.integration.factories import TestClientFactory
@pytest.mark.django_db(transaction=True)
def test_health_endpoint(test_client_factory: TestClientFactory) -> None:
client = test_client_factory()
response = client.get("/v1/health")
assert response.status_code == 200
assert response.json() == {"status": "ok"}
Fixtures¶
Core Fixtures¶
@pytest.fixture(scope="function")
def container() -> Container:
"""Fresh IoC container per test."""
return get_container()
@pytest.fixture(scope="function")
def test_client_factory(container: Container) -> TestClientFactory:
"""Test client factory with container isolation."""
return container.resolve(TestClientFactory)
@pytest.fixture(scope="function")
def test_client(test_client_factory: TestClientFactory) -> TestClient:
"""Pre-created test client."""
return test_client_factory()
User Fixtures¶
@pytest.fixture(scope="function")
def user_factory(transactional_db, container: Container) -> TestUserFactory:
"""Factory for creating test users."""
return container.resolve(TestUserFactory)
@pytest.fixture
def user(user_factory: TestUserFactory) -> User:
"""Pre-created test user."""
return user_factory()
Coverage Requirements¶
The project requires 80% test coverage: