【问题标题】:Test Django REST framework API response with nested resources使用嵌套资源测试 Django REST 框架 API 响应
【发布时间】:2016-05-12 17:58:47
【问题描述】:

我正在为项目编写一个 REST API,并且菜单端点正在返回一个 JSON,其中包含项目组、项目中的项目以及用户可以添加到项目中的任何额外内容。

serializers.py
====================
class ItemExtraSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = ItemExtra
        fields = ('id', 'name', 'price')


class ItemSerializer(serializers.HyperlinkedModelSerializer):
    extras = ItemExtraSerializer(many=True, read_only=True)

    class Meta:
        model = Item
        fields = ('id', 'url', 'name', 'description', 'image', 'code', 'price', 'extras')


class ItemGroupSerializer(serializers.HyperlinkedModelSerializer):
    items = ItemSerializer(many=True, read_only=True)

    class Meta:
        model = ItemGroup
        fields = ('id', 'url', 'name', 'items')


views.py
=========================
class MenuView(ListAPIView):
    serializer_class = ItemGroupSerializer

    def get_queryset(self):
        """
        Return the items inside their groups for search query
        Filtering is one Group name and Item name
        :return:
        """
        queryset = ItemGroup.objects.all()
        search_terms = self.request.query_params.get('q', None)
        if search_terms:
            queryset = Item.objects.search(search_terms)
        return queryset

tests.py
========================

class ItemTestCases(APITestCase):
    def setUp(self):
        self.sandwich_group, created = ItemGroup.objects.get_or_create(name='Sandwiches')
        self.meal_group, created = ItemGroup.objects.get_or_create(name='Meals')
        self.shawarma_sandwich, created = Item.objects.get_or_create(name='Shawarma Sandwich',
                                                                     description='Meat Shawarma Sandwich',
                                                                     price=1.250,
                                                                     code='SW-01',
                                                                     group=self.sandwich_group)
        self.burger_sandwich, created = Item.objects.get_or_create(name='Cheese Burger',
                                                                   description='Single cheese burger Sandwich',
                                                                   price=1.000,
                                                                   code='SW-02',
                                                                   group=self.sandwich_group)
        self.burger_sandwich_extra, created = ItemExtra.objects.get_or_create(name='Extra cheese',
                                                                              price=0.100,
                                                                              item=self.burger_sandwich)
        self.sharawma_meal, created = Item.objects.get_or_create(name='Shawarma Meal',
                                                                 description='Shawarma Sandwich with fries and drink',
                                                                 price=2.000,
                                                                 code='ME-01',
                                                                 group=self.meal_group)
        self.burger_meal, created = Item.objects.get_or_create(name='Burger Meal',
                                                               description='Single cheese burger Sandwich',
                                                               price=2.250,
                                                               code='ME-02',
                                                               group=self.meal_group)
        self.cheese_meal_extra, created = ItemExtra.objects.get_or_create(name='Extra cheese',
                                                                          price=0.100,
                                                                          item=self.burger_meal)
        self.factory = APIRequestFactory()



    def test_menu_GET_request(self):
       item_list = reverse('menu')
       response = self.client.get(item_list)
       self.assertEqual(response.status_code, status.HTTP_200_OK)
       groups = ItemGroup.objects.all()
       expected = ItemGroupSerializer(groups)
       self.assertContains(response, expected.data)

测试的输出是:

AssertionError:HyperlinkedIdentityField 需要序列化程序上下文中的请求。实例化序列化器时添加context={'request': request}

如何将 serlizer 呈现为 JSON,以便与 API 端点 JSON 进行比较?

更新 1: 我想通了,但我认为有一个更清洁的解决方案

我已经创建了辅助函数

def render_many_serializer_as_json(serializer, request, instance):
    serializer_data = serializer(instance=instance, many=True, context={'request': request}).data
    return JSONRenderer().render(serializer_data)

然后重写我的测试

def test_menu_GET_request(self):
        item_list = reverse('menu')
        request = self.factory.get(item_list, format='json')
        response = self.client.get(item_list)
        groups = ItemGroup.objects.all()
        expected = render_many_serializer_as_json(ItemGroupSerializer, request, groups)
        self.assertEqual(response.content, expected)

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    为什么要做复杂的事情? 只需明确写下预期的 JSON 输出:

    expected = {
        'id': 1,
        'name': ...,
        ...,
        'items': [{
            'id': ..,
            'url': ...,
        }]
    }
    

    【讨论】:

    • 因为如果我改变了序列化器结构怎么办,这种情况下我也想改变测试,写这么大的JSON很头疼。
    • 而且您将无法保证您的接口契约,因为如果序列化程序发生变化,您的接口也会发生变化,而这将被忽视。
    猜你喜欢
    • 2013-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    • 2018-12-08
    • 2014-12-15
    相关资源
    最近更新 更多