我怎样才能测试django消息?

dvy*_*dra 68 python django unit-testing django-testing

在我的django应用程序中,我正在尝试编写执行操作的单元测试,然后检查响应中的消息.

据我所知,没有很好的方法可以做到这一点.

我正在使用CookieStorage存储方法,我想做类似以下的事情:

    response = self.client.post('/do-something/', follow=True)
    self.assertEquals(response.context['messages'][0], "fail.")
Run Code Online (Sandbox Code Playgroud)

问题是,我得到的只是一个

print response.context['messages']
<django.contrib.messages.storage.cookie.CookieStorage object at 0x3c55250>
Run Code Online (Sandbox Code Playgroud)

我怎么能把它变成有用的东西,或者我做错了什么?

谢谢,丹尼尔

dav*_*ode 66

我找到了一个非常简单的方法:

response = self.client.post('/foo/')
messages = list(response.context['messages'])
self.assertEqual(len(messages), 1)
self.assertEqual(str(messages[0]), 'my message')
Run Code Online (Sandbox Code Playgroud)

如果需要检查没有上下文的响应的消息,可以使用以下命令:

from django.contrib.messages import get_messages
messages = list(get_messages(response.wsgi_request))
self.assertEqual(len(messages), 1)
self.assertEqual(str(messages[0]), 'my message')
Run Code Online (Sandbox Code Playgroud)

后备存储不支持索引,但它是可迭代的.

  • 如果你需要检查没有上下文的响应(例如重定向)的消息,你可以使用`list(r.wsgi_request._messages)` (4认同)
  • 看起来[0]在新版本上不起作用:`***TypeError:'FallbackStorage'对象不支持索引`.但是,它是一个Iterable,你可以使用任何`for m in messages`构造. (3认同)
  • 我还发现`self.assertEqual(m [0] .message,'my message')`有效 (2认同)
  • @Jonathan在一个测试用例里面的交互式调试器(`import ipdb; ipdb.set_trace()`)中使用`dir()`. (2认同)

ant*_*koo 17

这适用于我(显示所有消息):

print [m.message for m in list(response.context['messages'])]
Run Code Online (Sandbox Code Playgroud)

此外,我还有一些从Django的TestCase继承的测试类中的实用方法.如果您希望将它们作为函数,请删除self参数并将其替换self.fail()raise.

def assert_message_count(self, response, expect_num):
    """
    Asserts that exactly the given number of messages have been sent.
    """

    actual_num = len(response.context['messages'])
    if actual_num != expect_num:
        self.fail('Message count was %d, expected %d' %
            (actual_num, expect_num))

def assert_message_contains(self, response, text, level=None):
    """
    Asserts that there is exactly one message containing the given text.
    """

    messages = response.context['messages']

    matches = [m for m in messages if text in m.message]

    if len(matches) == 1:
        msg = matches[0]
        if level is not None and msg.level != level:
            self.fail('There was one matching message but with different'
                'level: %s != %s' % (msg.level, level))

        return

    elif len(matches) == 0:
        messages_str = ", ".join('"%s"' % m for m in messages)
        self.fail('No message contained text "%s", messages were: %s' %
            (text, messages_str))
    else:
        self.fail('Multiple messages contained text "%s": %s' %
            (text, ", ".join(('"%s"' % m) for m in matches)))

def assert_message_not_contains(self, response, text):
    """ Assert that no message contains the given text. """

    messages = response.context['messages']

    matches = [m for m in messages if text in m.message]

    if len(matches) > 0:
        self.fail('Message(s) contained text "%s": %s' %
            (text, ", ".join(('"%s"' % m) for m in matches)))
Run Code Online (Sandbox Code Playgroud)

  • 仅适用于显式ResponseContext或TemplateResponse(尝试构造ResponseContext). (2认同)

mop*_*pag 10

来自django文档:

在模板之外,您可以使用get_messages()

所以,你可以这样写:

from django.contrib.messages import get_messages

[...]

messages = [m.message for m in get_messages(response.wsgi_request)]
self.assertIn('My message', messages)
Run Code Online (Sandbox Code Playgroud)

  • 这应该是Django 2.1的公认答案 (2认同)