How to write concise CRUD tests in Django REST Framework

How to write concise CRUD tests in Django REST Framework
Photo by Hans Reniers / Unsplash

To write tests for Django REST framework's ListCreateAPIView and RetrieveUpdateDestroyAPIView, you will need to do the following:

  1. Set up your test environment and create a test case subclassing APITestCase from Django REST framework's test utilities.
  2. Define a test method in your test case for each view you want to test.
  3. Within each test method, use the client attribute of the test case to send requests to the view and make assertions about the response.

Here is an example of how you could write tests for a simple API that has a ListCreateAPIView for a Person model and a RetrieveUpdateDestroyAPIView for individual Person instances:


# myapp/models.py

class Person(models.Model):
    name = models.CharField(max_length=50)
    age = models.PositiveIntegerField(default=0)
    slug = models.CharField(max_length=50)


# myapp/rest/serializers.py

from rest_framework import serializers

from ..model import Person

class PersonSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Person
        fields = ('name', 'age', 'slug')


# myapp/rest/tests/test_people_endpoints.py

from rest_framework.test import APITestCase

from ...models import Person
from ..serializers import PersonSerializer

class PersonAPITestCase(APITestCase):
    def setUp(self):
        self.alice = {'name': 'Alice', 'slug': 'alice', 'age': 18}
        self.bob = {'name': 'Bob', 'slug': 'bob', 'age': 20}
        self.charlie = {'name': 'Charlie', slug: 'Charlie', 'age': 25}

    def test_post_peoplelist(self):
        # send a POST request to the ListCreateAPIView with the data for a new person
        response = self.client.post('/api/people', data=self.alice)
        # assert that the response status code is correct
        self.assertEqual(response.status_code, 201)
        # assert that the returned data is correct
        self.assertEqual(response.data, PersonSerializer(self.alice).data)

    def test_get_peoplelist(self):
        # send a GET request to the ListCreateAPIView
        response = self.client.get('/api/people')
        # assert that the response status code is correct
        self.assertEqual(response.status_code, 200)
        # assert that the returned data is correct
        self.assertEqual(response.data, PersonSerializer([self.bob, self.alice], many=True).data)

    def test_retrieve_person(self):
        # send a GET request to the RetrieveUpdateDestroyAPIView for an individual person
        response = self.client.get(f'/api/people/{self.bob.slug}')
        # assert that the response status code is correct
        self.assertEqual(response.status_code, 200)
        # assert that the returned data is correct
        self.assertEqual(response.data, PersonSerializer(self.bob).data)

    def test_update_person(self):
        payload = {'name': 'Robert', 'age': 31}
        # send a PUT request to the RetrieveUpdateDestroyAPIView with updated data for an individual person
        response = self.client.patch(f'/api/people/{self.bob.slug}', data=payload)
        # assert that the response status code is correct
        self.assertEqual(response.status_code, 200)
        # assert that the returned data is correct
        self.assertEqual(response.data, PersonSerializer(self.bob.update(payload)).data
        
    def test_destroy_person(self):
        # send a DELETE request to the RetrieveUpdateDestroyAPIView for an individual person
        response = self.client.delete('/api/people/{self.bob.slug}')
        # assert that the response status code is correct
        self.assertEqual(response.status_code, 204)
        # assert that the person was not in the list of people
        response = self.client.get('/api/people')
        self.assertNotIn(self.bob_data, response.data)