JavaRush /Курсы /Модуль 3: Django /Тестирование сериализаторов

Тестирование сериализаторов

Модуль 3: Django
22 уровень , 5 лекция
Открыта

Сегодня мы займемся тестированием сериализаторов (serializers), чтобы убедиться, что они корректно обрабатывают входящие данные и возвращают предсказуемые результаты. Ну и попутно вы узнаете о таких полезных инструментах, как фикстуры — чтобы тесты стали понятнее и удобнее.

Сериализаторы в Django REST Framework играют ключевую роль. Они служат "переводчиками" между Python-объектами (моделями) и форматом JSON (или другим представлением данных). Если сериализатор работает неправильно, ваше API может рассыпаться как карточный домик. Например:

  • Неправильная валидация данных может привести к сохранению некорректных записей в базу данных.
  • Ошибки в методах create() и update() могут повредить данные.
  • Некорректная настройка полей сериализатора приведет к тому, что пользователи API будут видеть и пользоваться неправильной структурой данных.

Тестирование сериализаторов поможет избежать подобных ситуаций. А главное — оно убережет вас от бессонных ночей перед дедлайном.

Задачи тестирования сериализаторов

Когда мы говорим о тестировании сериализаторов, основные задачи включают:

  1. Проверку, что сериализатор корректно "собирает" данные (пример: модель -> JSON).
  2. Проверку, что сериализатор валидирует данные так, как ожидается.
  3. Проверку правильной работы переопределенных методов, таких как create() и update().
  4. Проверку работы вложенных сериализаторов, если такие используются.
  5. Проверку того, что сериализатор возвращает необходимые ошибки, если данные некорректны.

Устройство теста для сериализатора: общий подход

Прежде чем перейти к коду, давайте уясним общую структуру тестов:

  1. Тестовые данные (входные данные и ожидаемый результат).
  2. Создание экземпляра сериализатора.
  3. Проверка:
    • Корректности сериализации (правильность выходных данных).
    • Валидации входных данных (как валидных, так и невалидных примеров).
    • Корректной работы методов create() и update().

Создание тестируемого сериализатора

Для примера будем использовать приложение для управления задачами. Вот упрощённая модель задачи:

# models.py
from django.db import models

class Task(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    is_completed = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

И соответствующий для неё сериализатор:

# serializers.py
from rest_framework import serializers
from .models import Task

class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = ['id', 'title', 'description', 'is_completed', 'created_at']

    # Переопределяем метод create, чтобы добавить логику
    def create(self, validated_data):
        validated_data['title'] = validated_data['title'].capitalize()
        return super().create(validated_data)

    # Переопределяем метод update, чтобы изменить логику обновления
    def update(self, instance, validated_data):
        if 'is_completed' in validated_data and validated_data['is_completed']:
            instance.description += "\nЗадача завершена."
        return super().update(instance, validated_data)

Написание тестов для сериализатора

Теперь перейдём к тестам!

Тестирование сериализации

Мы проверяем, что сериализатор правильно преобразует модель в JSON. Например:

# tests/test_serializers.py
from rest_framework.test import APITestCase
from tasks.models import Task
from tasks.serializers import TaskSerializer

class TaskSerializerTestCase(APITestCase):

    def test_task_serialization(self):
        """Проверка правильности сериализации Task -> JSON"""
        task = Task.objects.create(
            title="Test task",
            description="Description for test",
            is_completed=False
        )
        serializer = TaskSerializer(task)
        expected_data = {
            'id': task.id,
            'title': "Test task",
            'description': "Description for test",
            'is_completed': False,
            'created_at': task.created_at.isoformat()  # Дата в формате ISO
        }
        self.assertEqual(serializer.data, expected_data)

Тестирование валидации

Теперь проверяем валидацию входящих данных:

    def test_validation_success(self):
        """Проверка валидации корректных данных"""
        valid_data = {
            'title': "New Task",
            'description': "Task description",
            'is_completed': False
        }
        serializer = TaskSerializer(data=valid_data)
        self.assertTrue(serializer.is_valid())

    def test_validation_fail(self):
        """Проверка валидации некорректных данных"""
        invalid_data = {
            'title': "",  # Пустой заголовок
            'description': "Task description",
            'is_completed': False
        }
        serializer = TaskSerializer(data=invalid_data)
        self.assertFalse(serializer.is_valid())
        self.assertIn('title', serializer.errors)

Тестирование методов create и update

Теперь убедимся, что методы create() и update() работают как ожидается:

    def test_create_method(self):
        """Проверка метода create"""
        data = {
            'title': "new task",
            'description': "new description",
            'is_completed': False
        }
        serializer = TaskSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        task = serializer.save()

        self.assertEqual(task.title, "New task")  # Заголовок должен быть с большой буквы

    def test_update_method(self):
        """Проверка метода update"""
        task = Task.objects.create(
            title="Old task",
            description="Some description",
            is_completed=False
        )
        data = {'is_completed': True}
        serializer = TaskSerializer(task, data=data, partial=True)
        serializer.is_valid(raise_exception=True)
        updated_task = serializer.save()

        self.assertTrue(updated_task.is_completed)
        self.assertIn("Задача завершена.", updated_task.description)

Использование фикстур для тестирования

Чтобы не повторять код создания объектов в каждом тесте, можно использовать фикстуры. Это просто заранее подготовленные данные.

# tests/conftest.py
import pytest
from tasks.models import Task

@pytest.fixture
def task():
    return Task.objects.create(
        title="Fixture task",
        description="Fixture description",
        is_completed=False
    )

Теперь мы можем использовать их в тестах, указав имя фикстуры как аргумент функции:

def test_task_serialization_with_fixture(task):
    serializer = TaskSerializer(task)
    assert serializer.data['title'] == "Fixture task"

Полезные советы

  • Тестируйте каждый аспект в отдельности. Если ваш сериализатор сложный, создайте разные тестовые методы для проверки отдельных частей функционала.
  • Меньше повторений. Используйте фикстуры и вспомогательные функции для повторяющихся операций. Это сделает код тестов чище.
  • Не забудьте про отрицательные тесты. Убедитесь, что сериализатор корректно отлавливает невалидные данные и возвращает ожидаемые ошибки.

Заключение

Теперь вы умеете тестировать сериализаторы! Эти навыки помогут вам убедиться, что API работает корректно на уровне данных. Это не только улучшит ваш код, но и сделает жизнь проще для всех пользователей вашего API, включая ваш фронтенд-команду (которая, кстати, вас за это полюбит!).

Переходите к тестированию представлений, и да начнутся интеграционные тесты!

1
Задача
Модуль 3: Django, 22 уровень, 5 лекция
Недоступна
Тестирование сериализации данных
Тестирование сериализации данных
1
Задача
Модуль 3: Django, 22 уровень, 5 лекция
Недоступна
Проверка сериализатора с интеграцией модели
Проверка сериализатора с интеграцией модели
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ