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.
This first part 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.
Let’s begin.
1. 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.
2. Install pytest and Required Plugins
Install the packages:
pip install pytest pytest-django pytest-cov Faker
These tools give:
-
pytest— fast, expressive testing -
pytest-django— Django ORM, fixtures, DB setup -
pytest-cov— code coverage -
Faker— generating random test data
3. 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:
- You must explicitly point pytest to a test settings file.
-
--reuse-dbspeeds testing dramatically. -
-xstops after the first failure (optional but useful early on).
4. Create settings/test.py
Instead of reusing your local or production settings, create a lightweight test settings file:
from .local import *
DATABASES["default"]["NAME"] = "test_db"
AUTH_PASSWORD_VALIDATORS = []
TEST_USER = {
"id": 999,
"email": "testuser@example.com",
}
Important design decisions:
(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
This allows us to bypass complex signup flows (OTP, email verification, custom user manager logic).
5. PostgreSQL: Create a Dedicated Test Database
If you use PostgreSQL (most common in real DRF apps), create a test DB manually:
CREATE DATABASE test_db;
GRANT ALL PRIVILEGES ON DATABASE test_db TO your_db_user;
ALTER DATABASE test_db OWNER TO your_db_user;
This avoids the dreaded:
permission denied to create database
errors.
6. Add tests/ Directory Structure
Follow this recommended 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.
7. Create conftest.py with Critical Fixtures
Every DRF project needs these fixtures:
- An authenticated API client
- A test user
- Fixtures for foreign-key related models (Writer, Category, etc.)
Example:
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",
)
This ensures:
- No login/OTP/verification steps
- Reliable FK dependencies
- Authenticated API requests automatically
8. Running Tests for the First Time
pytest -s
If everything is configured correctly, you’ll see the test database created, and pytest will run successfully.
Part 2 will introduce complete DRF test cases using realistic model relationships.
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
- Reverse relationships
- Error validation tests
- Testing nested JSON structures
- Testing authenticated requests
Top comments (0)