Unit Testing API Endpoints0%

Unit Testing API Endpoints

Beginner12 min read•Updated: Jul 11, 2026
Study MaterialsCheatsheet

Unit Testing API Endpoints with APIClient and APITestCase

Testing REST APIs is critical for verifying endpoint contracts, status codes, payload structures, database mutations, and regression prevention. Django REST Framework provides testing utilities specifically designed for REST APIs that extend Django's core test framework.


1. APITestCase vs Standard TestCase

DRF provides rest_framework.test.APITestCase, which subclasses Django's django.test.TestCase but overrides the default client with DRF's APIClient.

FeatureDjango TestCase (Client)DRF APITestCase (APIClient)
Default Clientdjango.test.Clientrest_framework.test.APIClient
Payload FormattingExpects form-encoded data by defaultSupports format='json' natively
Authentication Helperclient.login() (session/cookie only)client.force_authenticate(user=user) (session, token, JWT)
Response HeadersGeneric WSGI responseFull access to response.data, parsed Python dictionary/list
Python
from rest_framework.test import APITestCase
from rest_framework import status
from django.contrib.auth import get_user_model
from store.models import Product
 
User = get_user_model()
 
class ProductAPITests(APITestCase):
def setUp(self):
self.user = User.objects.create_user(username='tester', password='securepassword123')
self.product = Product.objects.create(
title='Ergonomic Mechanical Keyboard',
price=129.99,
inventory=45,
sku='KB-MECH-01'
)
self.endpoint = '/api/v1/products/'
 
def test_list_products_returns_200_ok(self):
response = self.client.get(self.endpoint)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['results']), 1)
self.assertEqual(response.data['results'][0]['title'], 'Ergonomic Mechanical Keyboard')
 
def test_create_product_authenticated(self):
self.client.force_authenticate(user=self.user)
payload = {
'title': 'Wireless Mouse',
'price': 49.99,
'inventory': 100,
'sku': 'MS-WLS-02'
}
response = self.client.post(self.endpoint, payload, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Product.objects.count(), 2)
self.assertEqual(response.data['sku'], 'MS-WLS-02')

2. Inspecting response.data vs response.content

In DRF tests:

  • response.data: The parsed Python data structure (dict or list) before rendering to JSON string.
  • response.content: The raw byte string response (e.g., b'{"id":1,...}').
  • response.json(): Standard JSON parser parsing response.content.

Using response.data is fastest, cleanest, and most Pythonic in DRF unit tests:

Python
def test_product_detail_payload(self):
url = f'/api/v1/products/{self.product.id}/'
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn('sku', response.data)
self.assertEqual(float(response.data['price']), 129.99)

3. Testing HTTP Methods: PUT, PATCH, and DELETE

Python
def test_patch_partial_update(self):
self.client.force_authenticate(user=self.user)
url = f'/api/v1/products/{self.product.id}/'
patch_payload = {'price': 99.99}
response = self.client.patch(url, patch_payload, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.product.refresh_from_db()
self.assertEqual(float(self.product.price), 99.99)
 
def test_delete_product(self):
self.client.force_authenticate(user=self.user)
url = f'/api/v1/products/{self.product.id}/'
response = self.client.delete(url)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertFalse(Product.objects.filter(id=self.product.id).exists())

Interactive Quiz

Practice Quiz

Question 1
What is the primary advantage of using DRF's APITestCase over standard Django TestCase?
Question 2
What does response.data contain in a DRF APIClient test response?
Question 3
Why is self.product.refresh_from_db() called after a PATCH or PUT test request?
Question 4
Which format argument is passed into self.client.post(url, data, format='json')?
Question 5
What status code should a properly implemented DELETE endpoint return according to REST conventions?
Next Lesson

Using Django Test Client

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Related Lessons

Previous LessonNext Lesson
Best PracticesUsing Django Test Client

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext