如何对 django 消息进行单元测试?

发布于 2024-09-02 22:14:34 字数 490 浏览 4 评论 0原文

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

据我所知,没有什么好的方法可以做到这一点。

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

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

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

print response.context['messages']
<django.contrib.messages.storage.cookie.CookieStorage object at 0x3c55250>

如何将其变成有用的东西,或者我做的都是错的?

谢谢, 丹尼尔

In my django application, I'm trying to write a unit test that performs an action and then checks the messages in the response.

As far as I can tell, there is no nice way of doing this.

I'm using the CookieStorage storage method, and I'd like to do something similar to the following:

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

The problem is, all I get back is a

print response.context['messages']
<django.contrib.messages.storage.cookie.CookieStorage object at 0x3c55250>

How can I turn this into something useful, or am I doing it all wrong?

Thanks,
Daniel

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

万劫不复 2024-09-09 22:14:34

我发现了一个非常简单的方法:

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

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

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

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

I found a really easy approach:

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

If you need to check for messages on a response that has no context you can use the following:

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

The fallback storage doesn't support indexing, however it is an iterable.

南街女流氓 2024-09-09 22:14:34

来自 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)

From django documentation:

Outside of templates, you can use get_messages()

So, you could write something like:

from django.contrib.messages import get_messages

[...]

messages = [m.message for m in get_messages(response.wsgi_request)]
self.assertIn('My message', messages)

蒗幽 2024-09-09 22:14:34

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

print [m.message for m in list(response.context['messages'])]

另外,这里还有一些我在继承自 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)))

This works for me (displays all messages):

print [m.message for m in list(response.context['messages'])]

Also here are a couple of utility methods I have in a test class inherited from Django's TestCase. If you'd prefer to have them as functions, remove the self arguments and replace self.fail()'s with a 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)))
欢烬 2024-09-09 22:14:34

更新

我原来的答案是在 django 还是 1.1 左右的时候写的。这个答案不再相关。请参阅 @daveoncode 的答案以获得更好的解决方案。

原始答案

我做了一个实验来测试这一点。我将一个项目中的 MESSAGE_STORAGE 设置更改为 'django.contrib.messages.storage.cookie.CookieStorage' 并执行了我编写的用于检查消息的测试。它起作用了。

与您所做的主要区别在于我检索消息的方式。请参阅下文:

def test_message_sending(self):
    data = dict(...)
    response = self.client.post(reverse('my_view'), data)
    messages = self.user.get_and_delete_messages()

    self.assertTrue(messages)
    self.assertEqual('Hey there!', messages[0])

可能值得一试。

Update

My original answer was written when django was still 1.1 or so. This answer is no longer relevant. See @daveoncode's answer for a better solution.

Original Answer

I did an experiment to test this. I changed the MESSAGE_STORAGE setting in one of my projects to 'django.contrib.messages.storage.cookie.CookieStorage' and executed a test that I had written to check for messages. It worked.

The key difference from what you were doing is the way I retrieved messages. See below:

def test_message_sending(self):
    data = dict(...)
    response = self.client.post(reverse('my_view'), data)
    messages = self.user.get_and_delete_messages()

    self.assertTrue(messages)
    self.assertEqual('Hey there!', messages[0])

This may be worth a try.

梦里南柯 2024-09-09 22:14:34

我创建了一个 python 类来简化消息测试:

class TestMessageCase(TestCase):
""" class inherited from TestCase to add a function to test messages response """

def assertMessageContains(self, response, messages_list, debug=False):
    """
    Function to test messages returned by the response view

    :param response: The response of the view
    :param messages_list: An ordered list of messages to test
    :type messages_list: list of string
    :param debug: Show all response messages
    :type debug: bool
    """

    response_messages = list(response.context['messages'])

    if debug:
        print(
            " ---------------------------------------------------------------------\n",
            "|              DEBUG MESSAGES RETURNED BY THE RESPONSE              |\n",
            "---------------------------------------------------------------------"
        )
        for i in range(len(response_messages)):
            print(f"Message n°{i + 1} :\n{response_messages[i]}\n\n")
        print(
            " ---------------------------------------------------------------------\n",
            "|                             END DEBUG                             |\n",
            "---------------------------------------------------------------------"
        )

    self.assertEqual(len(response_messages), len(messages_list))
    for i in range(len(response_messages)):
        self.assertEqual(str(response_messages[i]), messages_list[i])

在测试函数中:

response = self.client.post('/foo/')
self.assertMessageContains(response, ["Foo"])

I created a python class to simplify messages testing :

class TestMessageCase(TestCase):
""" class inherited from TestCase to add a function to test messages response """

def assertMessageContains(self, response, messages_list, debug=False):
    """
    Function to test messages returned by the response view

    :param response: The response of the view
    :param messages_list: An ordered list of messages to test
    :type messages_list: list of string
    :param debug: Show all response messages
    :type debug: bool
    """

    response_messages = list(response.context['messages'])

    if debug:
        print(
            " ---------------------------------------------------------------------\n",
            "|              DEBUG MESSAGES RETURNED BY THE RESPONSE              |\n",
            "---------------------------------------------------------------------"
        )
        for i in range(len(response_messages)):
            print(f"Message n°{i + 1} :\n{response_messages[i]}\n\n")
        print(
            " ---------------------------------------------------------------------\n",
            "|                             END DEBUG                             |\n",
            "---------------------------------------------------------------------"
        )

    self.assertEqual(len(response_messages), len(messages_list))
    for i in range(len(response_messages)):
        self.assertEqual(str(response_messages[i]), messages_list[i])

And in test function :

response = self.client.post('/foo/')
self.assertMessageContains(response, ["Foo"])
猥︴琐丶欲为 2024-09-09 22:14:34

僵局的更简单版本:

class TestCaseMessagesMixture(object):
    def assertMessageCount(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 assertMessageEqual(self, response, text):
        """
        Asserts that the response includes the message text.
        """

        messages = [m.message for m in response.context['messages']]

        if text not in messages:
            self.fail(
                'No message with text "%s", messages were: %s' % 
                    (text, messages)
                )

    def assertMessageNotEqual(self, response, text):
        """
        Asserts that the response does not include the message text.
        """

        messages = [m.message for m in response.context['messages']]

        if text in messages:
            self.fail(
                'Message with text "%s" found, messages were: %s' % 
                    (text, messages)
                )

Simpler version of the stalemate one:

class TestCaseMessagesMixture(object):
    def assertMessageCount(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 assertMessageEqual(self, response, text):
        """
        Asserts that the response includes the message text.
        """

        messages = [m.message for m in response.context['messages']]

        if text not in messages:
            self.fail(
                'No message with text "%s", messages were: %s' % 
                    (text, messages)
                )

    def assertMessageNotEqual(self, response, text):
        """
        Asserts that the response does not include the message text.
        """

        messages = [m.message for m in response.context['messages']]

        if text in messages:
            self.fail(
                'Message with text "%s" found, messages were: %s' % 
                    (text, messages)
                )
剧终人散尽 2024-09-09 22:14:34

测试助手用于验证响应消息计数和内容

def get_response_messages(self, response):
    from django.contrib.messages import get_messages
    return list(get_messages(response.wsgi_request))


def check_response_messages(self, response, message_index=None, message_value=None, exp_count=None):
    messages = self.get_response_messages(response)
    if exp_count is not None:
        self.assertEqual(len(messages), exp_count)

    if message_index is not None:
        message = messages[message_index]
        self.assertIn(message_value, str(message))

可以像这样使用

message_value = "You can not switch to another type of account"
self.check_response_messages(response, exp_count=1, message_index=0, message_value=message_value)

Test helpers for validation of response messages count and content

def get_response_messages(self, response):
    from django.contrib.messages import get_messages
    return list(get_messages(response.wsgi_request))


def check_response_messages(self, response, message_index=None, message_value=None, exp_count=None):
    messages = self.get_response_messages(response)
    if exp_count is not None:
        self.assertEqual(len(messages), exp_count)

    if message_index is not None:
        message = messages[message_index]
        self.assertIn(message_value, str(message))

Can be used like this

message_value = "You can not switch to another type of account"
self.check_response_messages(response, exp_count=1, message_index=0, message_value=message_value)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文