Элегантный способ добавления тестового случая просмотра списка в 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, и во View есть логика для получения списка голодных собак. Я собираюсь сделать тест на логику получения списка голодных собак.

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 применяется Serializer, поэтому, когда он находится в форме 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?

Правильный подход действительно зависит от вашего списка View. Если вы тестируете работу простого сериализатора, как, например, этот:

class DogSerializer(serializers.ModelSerializer):
    class Meta:
        model = Dog
        fields = ['id', 'name', 'age', 'hungry', 'hurt']

С простым видом, как этот:

class HungryDogListView(ListAPIView):
    queryset = Dog.objects.filter(hungry=True)
    serializer_class = DogSerializer

Вы можете просто проверить, что ответ 200_OK и нужные идентификаторы в вашем списке:

def test_dog_hungry_list(self):
    response = self.client.get("/api/dog/hungry/")
    self.assertEqual(response.status_code, status.HTTP_200_OK)
    expected_ids = Dog.objects.filter(hungry=True).values_list("id", flat=True)
    response_ids = [dog['id'] for dog in response.data]
    self.assertEqual(set(response_ids), set(expected_ids))

Но если у вас хитрый сериализатор с некоторыми SerializerMethodField, то вы должны проверить не только идентификаторы, но и правильность вычисления этих полей:

class DogSerializer(serializers.ModelSerializer):
    is_injured_or_hungry = serializers.SerializerMethodField()
    age_in_dog_years = serializers.SerializerMethodField()

    class Meta:
        model = Dog
        fields = ['id','name', 'age', 'hungry', 'hurt', 'is_injured_or_hungry','age_in_dog_years']
    
    def get_is_injured_or_hungry(self, obj):
        return obj.hungry or obj.hurt

    def get_age_in_dog_years(self, obj):
        return obj.age * 7

В этом примере лучше всего проверить is_injured_or_hungry и age_in_dog_years

Кроме того, у вас может быть какая-то особая логика в представлении или даже в промежуточном ПО, которую необходимо проверить.

Так что простого ответа не существует. Все зависит от вашего конкретного случая

Вернуться на верх