All Django templates

Django Testing with pytest

pytest-django setup, fixtures, factories, and fast database tests.

DevZone Tools1,320 copiesUpdated Mar 9, 2026DjangoPython
# 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