Сьогодні ми займемося тестуванням серіалізаторів (serializers), щоб переконатися, що вони коректно обробляють вхідні дані та повертають передбачувані результати. Ну і заодно ви дізнаєтесь про такі корисні інструменти, як фікстури — щоб тести стали зрозумілішими та зручнішими.
Серіалізатори у Django REST Framework грають ключову роль. Вони слугують "перекладачами" між Python-об'єктами (моделями) і форматом JSON (або іншим представленням даних). Якщо серіалізатор працює неправильно, ваше API може розсипатися як картковий будинок. Наприклад:
- Неправильна валідація даних може призвести до збереження некоректних записів у базу даних.
- Помилки в методах
create()іupdate()можуть пошкодити дані. - Некоректне налаштування полів серіалізатора призведе до того, що користувачі API бачитимуть і використовуватимуть неправильну структуру даних.
Тестування серіалізаторів допоможе уникнути подібних ситуацій. А головне — воно збереже вас від безсонних ночей перед дедлайном.
Завдання тестування серіалізаторів
Коли ми говоримо про тестування серіалізаторів, основні завдання включають:
- Перевірку, що серіалізатор коректно "збирає" дані (приклад: модель -> JSON).
- Перевірку, що серіалізатор валідовує дані так, як очікується.
- Перевірку правильної роботи перевизначених методів, таких як
create()іupdate(). - Перевірку роботи вкладених серіалізаторів, якщо такі використовуються.
- Перевірку того, що серіалізатор повертає необхідні помилки, якщо дані некоректні.
Пристрій тесту для серіалізатора: загальний підхід
Перш ніж перейти до коду, давайте з’ясуємо загальну структуру тестів:
- Тестові дані (вхідні дані та очікуваний результат).
- Створення екземпляра серіалізатора.
- Перевірка:
- Коректності серіалізації (правильність вихідних даних).
- Валідації вхідних даних (як валідних, так і невалідних прикладів).
- Коректної роботи методів
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, включаючи твою фронтенд-команду (яка, до речі, тебе за це полюбить!).
Переходь до тестування представлень, і нехай розпочнуться інтеграційні тести!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ