Элегантный способ добавления тестового случая просмотра списка в 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.
Я придумал два следующих способа.
- Примените сериализатор к набору Queryset для сравнения. --> (Serializer(expected_response, many=True)))
- Сравните значения первичного ключа.
номер 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
Кроме того, у вас может быть какая-то особая логика в представлении или даже в промежуточном ПО, которую необходимо проверить.
Так что простого ответа не существует. Все зависит от вашего конкретного случая