A backend without tests is a backend you are afraid to change. After keeping a Django codebase at full backend coverage with pytest, here is the setup that made tests fast enough to actually run, and useful enough to actually trust.
The setup
Install pytest-django and point it at the settings module
in pytest.ini.
[pytest]
DJANGO_SETTINGS_MODULE = trampoline.settings
python_files = tests.py test_*.py *_tests.py
The database fixture
Tests do not touch the database unless they ask to. The
django_db mark grants access, which keeps pure unit tests
honest and fast.
import pytest
@pytest.mark.django_db
def test_order_defaults_to_received():
order = Order.objects.create(reference="PO-1")
assert order.status == "received"
Factories over fixtures of data
Hand-built test rows drift out of date. A factory builds a valid object with sensible defaults and lets each test override only the field it cares about.
import factory
class OrderFactory(factory.django.DjangoModelFactory):
class Meta:
model = Order
reference = factory.Sequence(lambda n: f"PO-{n}")
status = "received"
Test the API through the client
For endpoints, test through the framework test client. It exercises routing, authentication, serialization, and the view together, which is what a real caller hits. That is where the bugs that matter live.
Assert the query count
The django_assert_num_queries fixture turns a performance
regression into a failing test. If a change adds a hidden query, the
test catches it before production does.
Coverage that helps
Coverage measures which lines ran, not whether behavior was verified. Chasing a percentage for its own sake produces tests that execute code and assert nothing. Spend the effort on the unhappy paths: the rejected input, the permission denied, the conflicting update.
Keep the suite fast
Reuse the test database between runs, build objects in memory when a test does not need them persisted, and avoid the database entirely for logic that does not require it. A suite that runs in seconds gets run. A suite that takes ten minutes gets skipped.