Как выполнять интеграционное тестирование API в Django?

Ответ

Для интеграционного тестирования API в Django, особенно с использованием Django REST Framework, основным инструментом является APITestCase из rest_framework.test.

Он наследуется от django.test.TestCase, но предоставляет APIClient, который упрощает отправку HTTP-запросов (GET, POST и др.) и работу с JSON.

Основной процесс тестирования:

  1. Создание тестового клиента: APITestCase автоматически предоставляет self.client.
  2. Отправка запроса: Используйте методы клиента (self.client.post(), self.client.get()) для обращения к эндпоинту по его URL, который удобно получать через reverse().
  3. Проверка ответа (Assertions): Проверяется HTTP-статус ответа (например, status.HTTP_201_CREATED) и содержимое тела ответа (response.data).

Пример теста для эндпоинта создания пользователя:

from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
from django.contrib.auth.models import User

class UserAPITests(APITestCase):
    def test_create_user(self):
        """Убедимся, что мы можем создать нового пользователя."""
        url = reverse('user-list') # Предполагается, что URL-имя 'user-list'
        data = {'username': 'testuser', 'password': 'password123'}

        response = self.client.post(url, data, format='json')

        # 1. Проверяем успешный статус-код
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # 2. Проверяем, что пользователь действительно создан в БД
        self.assertEqual(User.objects.count(), 1)

        # 3. Проверяем данные в ответе
        self.assertEqual(User.objects.get().username, 'testuser')

Best practices:

  • Изоляция тестов: Каждый тест выполняется в изолированной транзакции, которая откатывается после его завершения. APITestCase делает это по умолчанию.
  • Подготовка данных: Используйте setUp или setUpTestData для создания необходимых объектов в базе данных перед тестом.
  • Проверка состояния: Убедитесь, что после выполнения запроса состояние системы (например, количество объектов в БД) изменилось ожидаемым образом.

Ответ 18+ 🔞

А, ну вот, смотри, смотри, блядь! Опять эти ваши тесты, API, Django... Ну ладно, разберёмся, как не остаться с носом, а точнее — с неработающим бэкендом.

Так вот, слушай сюда, сука. Есть у них в этом вашем Django REST Framework такая штука — APITestCase. Это типа как обычный TestCase, но с прикрученным ебучком для API. Он тебе сразу клиента подсовывает, self.client, который умеет в JSON и всякие POST-запросы слать, не как какой-нибудь тупорылый браузер.

Как это, блядь, работает, внатуре:

  1. Клиента достал. Он уже есть, self.client. Не надо его искать, он тут как тут, готовый впендюрить запрос куда надо.
  2. Запрос отправил. Берёшь этого клиента и говоришь: «Пошёл нахуй, сделай POST вот на этот URL (который через reverse() получишь, чтобы не как обезьяна строки вбивать) с вот такими данными».
  3. Ответ проверил. А вот тут, сука, самое интересное. Получил ответ и начинаешь его ёбать проверками. Статус-код правильный? 201 Created, а не 500 I'm a teapot? Данные в ответе те, что ожидал? И, что самое главное, блядь, в базе-то данных что-то изменилось? Создался ли пользователь, или это всё было как сон?

Вот, смотри, пример, чтобы не быть пиздаболом:

from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
from django.contrib.auth.models import User

class UserAPITests(APITestCase):
    def test_create_user(self):
        """Тест на то, что мы можем создать нового юзера, а не просто так пиздеть."""
        # 1. Говорим, куда стучаться
        url = reverse('user-list') # Имя урла, а не адресная строка, ёпта!
        # 2. Готовим данные, которые будем впихивать
        data = {'username': 'testuser', 'password': 'password123'}

        # 3. БАЦ! Отправляем запрос через нашего подставного клиента
        response = self.client.post(url, data, format='json')

        # 4. А теперь начинается проверка, блядь!
        # Во-первых, статус. Должен быть 201, а не 404 или 500.
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # Во-вторых, в базе данных должен появиться один пользователь. Раньше их было ноль.
        self.assertEqual(User.objects.count(), 1)

        # В-третьих, и этот пользователь должен быть именно тем, кого мы создали.
        self.assertEqual(User.objects.get().username, 'testuser')

А теперь, блядь, главные правила, чтобы не облажаться:

  • Тесты не должны друг другу мешать. APITestCase — молодец, он каждый тест запускает в своей песочнице (транзакции), а потом всё откатывает. Как будто ничего и не было. Никаких грязных следов.
  • Готовь данные заранее. Не надо в каждом тесте создавать одни и те же объекты. Используй setUp или setUpTestData. Это как подготовить инструменты перед ремонтом, а не бегать за каждой отвёрткой в магазин.
  • Проверяй не только ответ, но и последствия. Мало получить красивый JSON. Надо убедиться, что в системе что-то произошло. Объект создался? Удалился? Обновился? Вот это и есть суть, а не просто «запрос прошёл».

Вот и вся магия, ёпта. Ничего сложного, главное — не тупить и проверять всё, а не надеяться на авось.