DRF 测试:返回一个 OrderedDict 而不是 JSON

Posted

技术标签:

【中文标题】DRF 测试:返回一个 OrderedDict 而不是 JSON【英文标题】:DRF testing: instead of JSON an OrderedDict is returned 【发布时间】:2015-04-27 15:22:03 【问题描述】:

我正在尝试为 Django Rest 框架实现测试。 我的大部分测试都通过并且设置很顺利,但我现在遇到了一个问题,assertEqual 永远不会成功,因为它一直在将 JSON 与 OrderedDict 进行比较。

我不知道 OrderedDict 来自哪里,因为 DRF 应该只返回 JSON(对吗?)。

测试环境是否可能在比较之前解析 JSON?那会很糟糕。

我正在做一个集成测试,它只测试对某个资源的 GET 请求的响应中的数据,我基于 JSON 固定装置执行此操作。我没有测试 REST 框架的特定组件,因为我的组件实现非常简单,它们已经通过 DRF 项目中的测试进行了测试。

无论如何,我希望有人可以帮助我!

【问题讨论】:

您需要更加具体。序列化器负责将您的数据转换为字典,而渲染器将其转换为 JSON。你到底在测试哪个位? 已编辑!我已经解决了我的问题,我的固定装置有问题。但我仍然很好奇为什么它将 OrderedDict 与 JSON 进行比较而不是 JSON 与 JSON 进行比较,所以如果你有时间请回答:) 如果您需要确保响应 JSON 中键的顺序,则可以使用 OrderedDict 来编写响应。一旦它通过他的门并在野外它就变成了一个简单的 JSON,具有特定顺序的键。因为您使用的是 Django 测试基础架构,所以您的答案不会通过门,而是返回到您的测试用例以供您检查。这种行为使得最终测试 dict (JSON) 与 OrderedDict 成为可能。通常这应该不是问题:只需在各个键上断言即可。 【参考方案1】:

正如here 解释的那样,这是因为测试期间请求的默认格式是multipart 而不是json。您可以通过将格式提供给您的 api 调用来指定格式,如下所示:

response = self.client.get('/something/1', format='json')

或者您可以在settings.py 中设置默认测试请求格式,如下所示:

REST_FRAMEWORK = 
    'TEST_REQUEST_DEFAULT_FORMAT': 'json',  # Use application/json instead of multipart/form-data requests in tests.

自动为所有测试修复它。

【讨论】:

我不确定自这个答案以来这是否发生了变化,但现在的文档指出 format='json' 参数仅适用于“创建请求正文的方法”,因此不包括 GET 请求。我可以用我自己的代码以及阅读源代码来确认这一点(据我所知)。奇怪的是,文档中有一个示例,其中format 参数被传递给get() 方法。【参考方案2】:

听起来您正在使用 response.data(返回解析的 json 对象)而不是 response.content(给出原始 json 字符串)。

见http://www.django-rest-framework.org/api-guide/testing/#testing-responses

【讨论】:

【参考方案3】:

如果你的测试看起来像这样:

class SomeTests(APITestCase):
    def test_something(self):
        response = self.client.get('/something/1')
        # assertions with response

那么响应肯定是 OrderedDict 而不是 JSON 文档。幸运的是,Django 1.9 引入了response.json() 方法(https://docs.djangoproject.com/en/1.9/topics/testing/tools/#django.test.Response.json),因此您可以轻松地将响应转换为 JSON。请注意,您也可以使用 python 的 json 库。

这里的问题是 Django 的测试客户端(DRF 扩展)是一个“虚拟浏览器”(https://docs.djangoproject.com/en/1.9/topics/testing/tools/#the-test-client),它的工作方式与 Selenium 等浏览器内框架不同。因此,HTTP 调用实际上只是模拟的 HTTP 调用,专注于测试您的逻辑和正确的路由/视图/序列化器/等。正在使用中。

【讨论】:

【参考方案4】:

您可以将数据转储为 json 格式:

import json
return HttpResponse(json.dumps(data))

【讨论】:

@awwester 如果您觉得我的回答有帮助。请通过upvoting支持我。谢谢【参考方案5】:

我使用SerializerMethodField解决了这个问题。

简单地说,在序列化程序类中复制下最后 3 行并将 result 替换为导致问题的 json 成员

class ConfigSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Config
        fields = ('id', 'url', 'email', "result",)

    # COPY NEXT 3 LINES AND CHANGE 'result' WITH THE JSON MEMBER THAT CAUSE THE PROBLEM
    result = serializers.SerializerMethodField()
    def get_result(self, obj):
        return obj.result

result 之前显示为:

result: "OrderedDict([('key1', 1), ('key2', OrderedDict([('key3', [1, 2, 3])]))])"

解决后,result变成:

"result": "key1":1,"key2":"key3":[1,2,3]

【讨论】:

以上是关于DRF 测试:返回一个 OrderedDict 而不是 JSON的主要内容,如果未能解决你的问题,请参考以下文章

DRF json 404 而不是 html 页面

DRF--介绍和安装

drf自定义异常处理

DRF 之view

drf4 视图与路由组件

drf视图