Testing
Testing your API endpoints ensures reliability and prevents regressions as your application grows. DRF provides several specialized testing classes that extend Django's built-in testing framework, specifically designed to handle API-specific concepts like JSON serialization, authentication and HTTP status codes.
TIP
The primary difference between DRF's testing tools and Django's standard tools is that DRF's classes automatically handle content types, parse JSON responses and provide helpers for API authentication. This reduces boilerplate and keeps your test code DRY.
Core Test Classes
DRF provides three main classes for testing APIs, each serving a different pedagogical purpose:
APITestCase: The standard way to write integration tests. It extends Django'sTestCase.APIClient: The underlying mock web browser used byAPITestCaseto make requests.APIRequestFactory: A lower-level utility for testing views in isolation without routing through the URL dispatcher.
APITestCase
APITestCase is the most common class you'll use. It extends Django's TestCase, but replaces the standard Django Client with DRF's APIClient.
This is the recommended approach because it tests your API end-to-end, including URL routing, permissions, authentication and view logic.
Writing Your First Test
Here is an example of testing an endpoint that creates a new user.
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from .models import Account
class AccountTests(APITestCase):
def test_create_account(self):
"""
Ensure we can create a new account object.
"""
url = reverse('account-list')
data = {'name': 'DabApps'}
# Make the POST request
response = self.client.post(url, data, format='json')
# Verify the response
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Account.objects.count(), 1)
self.assertEqual(Account.objects.get().name, 'DabApps')Explaining the Defaults
Notice the format='json' argument in .post().
By default, if you don't specify a format, DRF's test client encodes data as multipart/form-data. While this is useful for testing file uploads, most modern REST APIs expect JSON. Passing format='json' tells the test client to encode the Python dictionary data into a JSON string and set the Content-Type: application/json header.
NOTE
You can change the default format globally in your settings.py by setting TEST_REQUEST_DEFAULT_FORMAT to 'json'.
Authentication in Tests
When testing protected endpoints, you need a way to authenticate your test requests. While you could manually pass headers or log in through an endpoint, DRF provides helpers to do this directly and efficiently.
Forcing Authentication
The .force_authenticate() method allows you to bypass the standard authentication mechanisms (like checking passwords or validating tokens) and explicitly force a request to run as a specific user.
This keeps your tests fast and focused on the view logic, rather than re-testing your authentication backend on every single endpoint.
from django.contrib.auth.models import User
from rest_framework.test import APIClient
class ProtectedEndpointTests(APITestCase):
def setUp(self):
# Create a test user
self.user = User.objects.create_user(username='admin', password='password123')
def test_restricted_data_access(self):
# Force the client to run as our test user
self.client.force_authenticate(user=self.user)
# Now the request will be fully authenticated
response = self.client.get('/api/restricted/')
self.assertEqual(response.status_code, 200)
# To clear authentication for subsequent requests:
self.client.force_authenticate(user=None)Passing Specific Credentials
If you want to test the actual authentication mechanism (e.g., ensuring a specific token format works), you can set the exact headers using .credentials().
def test_token_auth(self):
# Set the exact HTTP header that the client would send
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)
response = self.client.get('/api/restricted/')
self.assertEqual(response.status_code, 200)
# Clear credentials
self.client.credentials()APIRequestFactory
While APITestCase tests the full request-response cycle, APIRequestFactory is a lower-level tool. It creates mock Request objects that you can pass directly into your view functions or classes.
Why Use APIRequestFactory?
You should use APIRequestFactory when you want to write unit tests for a view, completely bypassing Django's middleware and URL routing. This is faster but less comprehensive than APITestCase.
Example Usage
from rest_framework.test import APIRequestFactory
from .views import UserListView
def test_user_list_view():
factory = APIRequestFactory()
# Create the mock request
request = factory.get('/users/', format='json')
# Call the view directly
view = UserListView.as_view()
response = view(request)
assert response.status_code == 200WARNING
Requests generated by APIRequestFactory do not pass through Django's middleware. If your view relies on attributes set by middleware (like request.session), you must manually attach them to the request before calling the view.
Advanced Test Cases
DRF also includes specialized test cases that mirror Django's advanced testing classes:
APITransactionTestCase: Use this if you need to test transactions, such as committing or rolling back data within the test. Slower thanAPITestCase.APISimpleTestCase: Use this when your tests do not require database access.APILiveServerTestCase: Launches a live Django server in the background, useful for running integration tests with browser automation tools like Selenium or Playwright.
