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的主要内容,如果未能解决你的问题,请参考以下文章