Introducing Automated Testing Late in a Django + DRF Project: Setup, Requirements, and Best Practices - Part-1
Source: Dev.to
Many Django REST Framework projects begin with rapid feature development and no automated test suite. At first this feels productive, but as foreign keys grow, serializers become nested, and the system gains complexity, manual testing becomes fragile and extremely time‑consuming.
This two‑part series shows exactly how to introduce pytest into an existing Django REST Framework project, even if you’re deep into development.
Part 1 covers
- Why pytest is ideal for Django + DRF
- Installing pytest and configuring project‑level settings
- Creating a separate test settings file
- Setting up a dedicated PostgreSQL test database
- Building fixtures for API clients and test users
- Handling custom user models safely
- Preparing your project to run tests reliably
Part 2 will show real‑world test cases using a Blog → Writer → Category → SocialMediaMeta use case.
Why Add Tests at a Later Stage?
Many teams postpone testing until:
- Models are stabilized
- Views and serializers begin accumulating logic
- Manual testing becomes slow or error‑prone
- Refactoring becomes risky
- Bugs begin recurring
- Onboarding new developers becomes cumbersome
Good news: pytest integrates cleanly even in a large, fully active Django project, as long as you separate your test configuration correctly.
Install pytest and Required Plugins
pip install pytest pytest-django pytest-cov Faker
These tools provide:
pytest– fast, expressive testingpytest-django– Django ORM, fixtures, DB setuppytest-cov– code coverageFaker– generating random test data
Create pytest.ini in Project Root
[pytest]
DJANGO_SETTINGS_MODULE = project.settings.test
python_files = tests.py test_*.py *_tests.py
addopts = --reuse-db -x
Key points
- Explicitly point pytest to a test settings file.
--reuse-dbspeeds testing dramatically.-xstops after the first failure (optional but useful early on).
Create settings/test.py
from .local import *
DATABASES["default"]["NAME"] = "test_db"
AUTH_PASSWORD_VALIDATORS = []
TEST_USER = {
"id": 999,
"email": "testuser@example.com",
}
(a) Separate database
Tests must not touch your development DB.
(b) Disable password validators
Tests should not fail due to password complexity requirements.
(c) TEST_USER
Allows bypassing complex signup flows (OTP, email verification, custom user manager logic).
PostgreSQL: Create a Dedicated Test Database
CREATE DATABASE test_db;
GRANT ALL PRIVILEGES ON DATABASE test_db TO your_db_user;
ALTER DATABASE test_db OWNER TO your_db_user;
Creating the DB manually avoids the dreaded:
permission denied to create database
Add tests/ Directory Structure
tests/
│── __init__.py
│── conftest.py
│── test_blog_creation.py
│── test_blog_listing.py
│── test_nested_blog_response.py
│── test_signals_blog_metadata.py
The key file here is conftest.py.
Create conftest.py with Critical Fixtures
import pytest
from django.contrib.auth import get_user_model
from blogs.models import Writer, Category
@pytest.fixture
def test_user(db, settings):
User = get_user_model()
data = settings.TEST_USER
return User.objects.create(
id=data["id"],
email=data["email"],
is_active=True,
)
@pytest.fixture
def api_client(test_user):
from rest_framework.test import APIClient
client = APIClient()
client.force_authenticate(test_user)
return client
@pytest.fixture
def writer(db):
return Writer.objects.create(
name="Jane Writer",
email="jane@example.com",
)
@pytest.fixture
def category(db):
return Category.objects.create(
title="Technology",
slug="tech",
)
These fixtures provide:
- An authenticated API client (no login/OTP steps)
- A reusable test user
- Reliable foreign‑key dependencies
Running Tests for the First Time
pytest -s
If everything is configured correctly, pytest will create the test database and run the tests successfully.
Next in Part 2: Real‑World DRF Testing Use Cases
In the next section we will cover:
- Blog + Writer + Category + SocialMediaMeta sample models
- Nested serializers
- Foreign‑key creation tests
- Signals and reverse relationships
- Error‑validation tests
- Testing nested JSON structures
- Testing authenticated requests