How can I unit test django messages?

前端 未结 6 650
南笙
南笙 2020-12-24 04:08

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 n

相关标签:
6条回答
  • 2020-12-24 04:52

    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.

    0 讨论(0)
  • 2020-12-24 04:54

    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)
                    )
    
    0 讨论(0)
  • 2020-12-24 04:55

    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)
    

    0 讨论(0)
  • 2020-12-24 05:02

    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)))
    
    0 讨论(0)
  • 2020-12-24 05:03

    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)
    
    0 讨论(0)
  • 2020-12-24 05:05

    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.

    0 讨论(0)
提交回复
热议问题