繁体   English   中英

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

[英]Django test Client submitting a form with a POST request

如何使用 Django 测试客户端提交 POST 请求,以便在其中包含表单数据? 特别是,我想要类似的东西(灵感来自How should I write tests for Forms in 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') 时,我什么也得不到。 我找到了解决方案,所以我在下面分享。

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

from urllib import urlencode

...

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

希望这可以帮助某人!

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

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')

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

我已经尝试使用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()替换为实际的 function 名称。 此 function 向正在使用表单字段“某物”及其对应值进行测试的视图发送 POST 请求。 然而,断言语句将完全取决于测试函数的效用。 以下是一些可能会用到的断言:

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

如果视图 function 也使用 Django 消息框架来显示表单错误消息,请在响应之前包含以下内容:

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

如果视图 function 使用会话,请在响应之前包含此内容:

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 请求和 forms 的所有可能的测试用例。

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

Harry JW Percival 在他的书Test-Driven Development with Python中提到了这种技术。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM