Элегантный способ добавить тестовый случай для представления списка в DRF.

Вопрос или проблема

У меня есть одна проблема при написании тестового кода для списка.

Для списка DRF ответ включает несколько данных.

Что мне делать, если я предполагаю, что объект response.data является моделью с множеством полей?

response.data --> [{"id": 1, "field1": "xxx", "field2": "yyy"....}, {"id": 2, ...}, ...]

Для сопоставления со статическими данными требуется слишком много входных данных, когда возвращается много полевых данных.

def test_xx(self):
    self.assertEqual(response.data, [{"id": 1, "field1": "xxx", ..., "field12": "ddd", ...}, ...])

В настоящее время я пришел к следующему способу.

Я создал пример модели под названием Dog.

class Dog(models.Model):
    ...
    hungry = models.BooleanField(default=False)
    hurt = models.BooleanField(default=False)

Например, пусть будет класс Dog, и в представлении есть логика для получения списка голодных собак.
Я собираюсь сделать тест на логику получения списка голодных собак.

class ...
    def test_dog_hungry_list(self):
        response = client.get("/api/dog/hungry/")
        expected_response = Dog.objects.filter(hungry=True)
        self.assertEqual(response.data, expected_response)

Два значения, которые я хочу сравнить с assertEqual, response и expected_response, имеют разные типы.

  • response –> Response
  • expected_response –> Queryset

В случае response.data остается применить сериализатор, поэтому, когда он находится в формате dict, я хочу сравнить его с типом Queryset expected_response.

Я подумал о двух способах как следует.

  1. Применить сериализатор к Queryset для сравнения. –> (Serializer(expected_response, many=True))
  2. Сравнить значения первичных ключей.

пример номер 2.

expected_response = Dog.objects.filter(hungry=True).values("id")
self.assertEqual(
[data["id"] for data in response.data],
[data["id"] for data in expected_response]
)

Но я не уверен, являются ли два метода хорошими для сравнения.

Есть ли способ сделать данные разумными для сравнения, когда тестовый код возвращает два или три данных в форме большого dict?

Ответ или решение

Для написания тестов для представлений списка (list view) в Django REST Framework (DRF), особенно когда ваша модель имеет множество полей, действительно важно находить элегантный и эффективный способ проверки данных ответа. Приведу несколько примеров и рекомендаций по этому вопросу.

Подходы к тестированию

1. Сравнение путем сериализации QuerySet

Первый и наиболее распространенный способ — это сериализация ожидаемого QuerySet, как вы уже упомянули. Это позволит вам привести данные из базы к тому же формату, который возвращает ваш API.

Пример кода:

from rest_framework.test import APITestCase
from myapp.models import Dog
from myapp.serializers import DogSerializer

class DogListTestCase(APITestCase):
    def setUp(self):
        # Создаем тестовые данные
        Dog.objects.create(id=1, hungry=True, hurt=False)
        Dog.objects.create(id=2, hungry=True, hurt=True)
        Dog.objects.create(id=3, hungry=False, hurt=False)

    def test_dog_hungry_list(self):
        response = self.client.get("/api/dog/hungry/")
        expected_response = Dog.objects.filter(hungry=True)
        expected_data = DogSerializer(expected_response, many=True).data

        self.assertEqual(response.data, expected_data)

В этом примере мы сериализуем expected_response, чтобы проверить его с данными, возвращенными API.

2. Сравнение по ключевым полям

Если количество полей в ответе велико, и вас интересуют только некоторые ключевые атрибуты, вы можете ограничиться сравнением значений конкретных полей, таких как id. Это позволяет сократить объем требуемого кода и все еще дает вам уверенность в корректности ответа.

Пример кода:

def test_dog_hungry_ids(self):
    response = self.client.get("/api/dog/hungry/")
    expected_ids = Dog.objects.filter(hungry=True).values_list("id", flat=True)

    self.assertEqual(
        sorted([dog["id"] for dog in response.data]),
        sorted(expected_ids),
    )

В этом случае сравниваются только id, что значительно упрощает тест.

3. Использование визуализации данных

Если вы ожидаете, что ответ будет включать много полей, вы можете использовать assertListEqual, чтобы сравнить списки объектов или словарей. Назовем это "глубоким сравнением", если вы хотите проверить определенные атрибуты.

def test_dog_hungry_list_deep_compare(self):
    response = self.client.get("/api/dog/hungry/")
    expected_data = Dog.objects.filter(hungry=True).values()

    response_data = response.data
    self.assertListEqual(sorted(response_data, key=lambda x: x['id']), sorted(expected_data, key=lambda x: x['id']))

Заключение

Выбор метода зависит от ваших целей и структуры данных. Если вам нужно проверить конкретные поля, используйте подход с сериализацией, а если достаточно проверки ключевых идентификаторов, второй вариант будет более эффективным. Важно стремиться к балансу между полнотой теста и его удобством.

При использовании DRF всегда лучше ориентироваться на читаемость и поддерживаемость кода тестов, чтобы другие разработчики могли быстро понять логику тестирования.

Оцените материал
Добавить комментарий

Капча загружается...