Django 测试客户端通过 POST 请求提交表单

问题描述 投票:0回答:4

如何使用 Django 测试客户端提交 POST 请求,以便在其中包含表单数据? 特别是,我想要类似的东西(灵感来自我应该如何在 Django 中为表单编写测试?):

from django.tests import TestCase

class MyTests(TestCase):
    def test_forms(self):
        response = self.client.post("/my/form/", {'something':'something'})

我的端点 /my/form 有一些内部逻辑来处理“某事”。 问题是,当尝试稍后访问 request.POST.get('something') 时,我无法得到任何东西。 我找到了解决方案,所以我在下面分享。

python django django-testing
4个回答
26
投票

关键是在客户端的post方法中添加content_type,并对数据进行urlencode。

from urllib.parse import urlencode

...

data = urlencode({"something": "something"})
response = self.client.post("/my/form/", data, content_type="application/x-www-form-urlencoded")

希望这对某人有帮助!


3
投票

如果您使用 client 在旧 django 版本上发送字典,则必须定义 content_type='application/json' 因为它的内部转换无法处理字典,您还需要使用像 blob 一样发送字典json.dumps方法。总之,以下几点必须有效:

import json
from django.tests import TestCase

class MyTests(TestCase):
    def test_forms(self):
        response = self.client.post("/my/form/", json.dumps({'something':'something'}), content_type='application/json')

1
投票

我尝试使用 Client() 在 Django 中对 POST 请求进行单元测试,但我未能使其工作(即使使用上面指定的方法)。因此,这是我专门用于 POST 请求的另一种方法(使用 HttpRequest()):

from django.http import HttpRequest
from django.tests import TestCase
from . import views
# If a different test directory is being used to store the test files, replace the dot with the app name

class MyTests(TestCase):
    def test_forms(self):
        request = HttpRequest()
        request.method = 'POST'
        request.POST['something'] = 'something'
        request.META['HTTP_HOST'] = 'localhost'
        response = views.view_function_name(request)
        self.assertNotIn(b'Form error message', response.content)
        # make more assertions, if needed

view_function_name() 替换为实际函数名称。该函数向正在测试的视图发送一个 POST 请求,其中包含表单字段“something”及其相应的值。然而,断言语句完全取决于测试函数的实用性。 以下是一些可以使用的断言:

  • self.assertEquals(response.status_code, 302)
    : 当表单在提交 POST 请求时重定向(302 是重定向的状态代码)时,进行此断言。阅读更多相关信息这里
  • self.assertNotIn(b'Form error message', response.content)
    : 将“表单错误消息”替换为通过请求发送不正确的详细信息时表单生成的错误消息。如果测试数据不正确,测试将失败(文本会转换为字节,因为 HttpResponse().content 也是字节对象)。

如果视图函数也使用 Django Message 框架来显示表单错误消息,请在 response 之前包含此内容:

from django.contrib import messages
...
request._messages = messages.storage.default_storage(request)

如果视图函数使用会话,请在 response 之前包含此内容:

from importlib import import_module
from django.conf import settings
...
engine = import_module(settings.SESSION_ENGINE)
session_key = None
request.session = engine.SessionStore(session_key)

在发送请求之前,请记住您的应用程序可能使用的任何上下文处理器的用途。

我个人觉得这种方法更直观(也更实用)。这似乎也涵盖了有关 HTTP 请求和表单的所有可能的测试用例。

我还想建议每个单元测试用例可以分解为单独的组件,以增加覆盖范围并发现代码中的潜在错误,而不是将所有用例集中在一个 test_forms() 中。

Harry J.W. 提到了这项技术。 Percival 在他的书中使用 Python 进行测试驱动开发


0
投票

如果您将 content_type 提供为

application/json
,则数据将使用
json.dumps()
进行序列化(如果它是字典、列表或元组)。默认情况下使用
DjangoJSONEncoder
执行序列化,并且可以通过向
json_encoder
提供
Client
参数来覆盖序列化。 put()、patch() 和 delete() 请求也会发生这种序列化。

© www.soinside.com 2019 - 2024. All rights reserved.