Django Testing with pytest
pytest-django setup, fixtures, factories, and fast database tests.
# CLAUDE.md — Django Testing with pytest
## Setup
- Use **pytest** with **pytest-django**. Don't write `unittest`-style `TestCase` subclasses for new tests.
- Config in `pyproject.toml`:
```toml
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "myproject.settings.test"
python_files = ["tests.py", "test_*.py", "*_tests.py"]
addopts = "--reuse-db --nomigrations"
```
- `--reuse-db` keeps the test DB across runs. `--nomigrations` skips migrations and uses syncdb-style schema creation — much faster.
## Fixtures
- One `conftest.py` per app for app-local fixtures. One root `conftest.py` for project-wide fixtures.
- Don't use Django's `fixtures` JSON. Build state with **factory_boy** (`factory.django.DjangoModelFactory`).
- Factories live in `<app>/tests/factories.py`. One factory per model. Use `Faker` for realistic strings.
## Database access
- Mark tests that hit the DB with `@pytest.mark.django_db`. Untouched code stays fast.
- For complex transactional tests, use `@pytest.mark.django_db(transaction=True)` — but it's slower, so reach for it only when needed.
- Each test gets a clean DB via transaction rollback. Don't write tests that depend on order.
## API tests
- DRF tests use `APIClient` from a fixture. Pass `format='json'` explicitly.
- Authentication: `client.force_authenticate(user=user)`. Don't fake auth via session middleware in tests.
- Assert on status code, response shape, and side effects. A passing 200 with a wrong body is still a bug.
## Mocks
- Use `pytest-mock` (`mocker.patch`) — cleaner than the bare `unittest.mock`.
- Patch where the symbol is **used**, not where it's defined.
- Don't mock the framework. If you find yourself mocking `Model.objects.filter`, the test is at the wrong level.
## Speed
- Run tests in parallel with `pytest-xdist`: `pytest -n auto`.
- Profile with `pytest --durations=10`. Anything over a second is suspicious.
- Don't sleep in tests. Use `freezegun` or pass time as a parameter.
## Coverage
- `pytest-cov` for coverage. Aim for high coverage on services and models; tests of view scaffolding rarely matter.
- Don't chase 100% by testing trivial code. Cover the branches that hide bugs.
## Don't
- Don't load fixtures from JSON files in 2025+. Use factories.
- Don't share state between tests via module-level mutable variables.
- Don't catch and swallow exceptions in tests to "make them pass". Fix the cause.
- Don't run tests against a real external API. Mock at the boundary, integration-test in a separate stage.
Other Django templates
Django + DRF Rules
Django REST Framework conventions: viewsets, serializers, permissions.
Django Models + ORM Discipline
Model design, migrations, queryset hygiene, and N+1 prevention.
Django + Celery Background Jobs
Celery task design, idempotency, retries, and Redis as broker.
Django Deployment (Docker + gunicorn)
Production deploy: Docker images, gunicorn, env management, static files.