单元测试 Django JSON 视图

Posted

技术标签:

【中文标题】单元测试 Django JSON 视图【英文标题】:Unit testing Django JSON View 【发布时间】:2011-06-15 05:35:39 【问题描述】:

我正在尝试为一些 Django json_view 视图编写一些单元测试,但我无法将 json_string 传递给视图。我昨天发布了一个有关从 JS 将 json 字符串传递给 Django 视图的相关问题,问题是在我的 JS 中我只是传递了 json 字符串,我需要将字符串作为对象的属性传递,因为我未能做到这一点,字符串被视为结果查询字典的键。我又遇到了类似的问题,只是这次它是对 Django View 的 Django 单元测试。这是我的代码的简化版本,它产生相同的结果。

class MyTestCase(TestCase):
    def setUp(self):
        self.u = User.objects.create_user('test','test','test')
        self.u.is_active = True
        self.u.save()
        self.client.login(username='test',password='test')

    def test_create_object_from_form(self):
        """Test the creation of the Instance from the form data."""
        import json
        json_string json.dumps('resource':'type':'book','author':'John Doe')
        print(json_string)
        response = self.client.post(reverse('ajax_view'),
                                    'form':json_string,'json')
        self.assetNotContains(response,'error')

视图看起来像这样

@json_view
def ajax_view(request):
    """Process the incoming form data."""
    if request.method == 'POST':
        print(request.POST)
        form_data = json.loads(request.POST['form'])
        resource_data = form_data['resource']
        form = MyUserForm(resource_data)

        if form.is_valid():
        ...

这是运行测试时两个打印语句产生的结果。 json_string 是

"resource": "type": "book", "author": "John Doe"

查询字典看起来像

<QueryDict: u'\'form\': \'"resource": "type": "book", "author": "John Doe"\'': [u'']>

我完全是 JS 和 ajax 的新手,所以不要担心伤害我的自尊心,答案可能很接近它可能会跳起来咬我。

【问题讨论】:

【参考方案1】:

最终编辑

我最初声明标题 HTTP_X_REQUESTED_WITH='XMLHttpRequest' 在 post 调用中是必需的,但目前在测试中这是错误的。此标头对于 csrf 中间件是必需的,但 csrf 在测试中被禁用。但是,即使中间件禁用 csrf,我仍然认为进行测试是一个好习惯,因为大多数 javascript 库在执行 ajax 时已经默认传递了此标头。此外,如果另一段未被禁用的代码曾经使用过 is_ajax 方法,则您无需花费数小时调试单元测试来确定缺少标头。

问题出在内容类型上,因为当 django 得到一个不同于 text/html 的值时,它不使用默认的发布数据处理,即像在查询中那样格式化您的数据:@987654323 @ 例如。

那么固定的代码就是:

response = self.client.post(reverse('ajax_view'),
                            'form':json_string, 
                            HTTP_X_REQUESTED_WITH='XMLHttpRequest')

这是我自己的使用方法:

post_data =  
    "jsonrpc" : "2.0", "method": method, "params" : params, "id" : id 
return client.post('/api/json/', 
                    json.dumps(post_data), "text/json",            
                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')

做一些json-rpc。请注意,由于我传递的内容类型与默认值不同,因此我的数据在发布请求中按原样传递。

【讨论】:

即使添加了标头“XMLHttpRequest”,我仍然会在查询字典的关键位置获得 JSON 字符串。 删除您如何使用 client.post 的第二个示例,我会将其标记为答案,第二个示例包含我创建帖子要解决的问题。 嗯,抱歉,第二个示例来自我的代码库,与我的 json 装饰器完美配合。请记住,我正在做的 json-rpc 与您的用例不同。 如果它可以帮助其他人,我正在研究 django-piston API,发现它默认拒绝'text/json',但接受'application/json【参考方案2】:

感谢@Eric_Fortin 让我打开标题,但是它并没有解决我使用“client.post”的格式错误的查询字典的问题。一旦我使用 XMLHttpRequest 标头从 POST 更改为 GET,我的查询字典就会变得狭窄。这是当前的解决方案:

response = self.client.get(reverse('ajax_view'),
                           'form':json_string,'json',
                           HTTP_X_REQUESTED_WITH='XMLHttpRequest')

这只是部分答案,因为此请求将更改服务器上的数据,并且应该是 POST 而不是 GET。

编辑:

这是我的测试中用于通过 POST 将 JSON 字符串传递到我的视图的最终代码:

response = self.client.post(reverse('ajax_view'),
                            'form':json.dumps(json_dict))

现在从视图中打印显示查询字典格式正确。

<QueryDict: u'form': [u'"resource": "status": "reviewed", "name": "Resource Test", "description": "Unit Test"']>

我在与我的一位同事修补时找到了答案,删除 content_type 'json' 修复了格式错误的查询字典。正在测试的视图不使用或调用“HttpRequest.is_ajax()”,发送标头 XMLHttpRequest 对我的问题没有影响,尽管包含标头将构成良好的形式,因为这篇文章是一个 ajax 请求.

【讨论】:

错了,它也适用于 post。查看我编辑的回复。 尽管如此,即使更改代码以便将 json 字符串直接作为 'post' 方法的 'data' 参数提供,我的查询字典仍然会在我的 'view' 中与 json 字符串一起出现在关键。将方法从“post”更改为“get”并将引用的 json_string 作为字典的值,查询字典的结构正确。我坚持我的回应。 编辑了我的答案以解释问题并详细说明解决方案。 我承认标头的发送是良好的形式,因为这篇文章是一个 ajax 请求,尽管包含标头对我的问题没有影响,即查询字典的格式错误。仅提供 json_string 作为“client.post”方法的第二个参数会导致查询字典格式错误。当 content_type 设置为 'text/json' 或只是 'json' 时,'client.post' 生成的查询字典也会出现格式错误。

以上是关于单元测试 Django JSON 视图的主要内容,如果未能解决你的问题,请参考以下文章

为视图编写 Django 单元测试 [重复]

python django单元测试文件字段视图示例

python django单元测试文件字段视图示例

python django单元测试文件字段视图示例

Django单元测试中Fixtures用法

在 Django 单元测试中使用会话对象