Django Testing - check messages for a view that redirects

戏子无情 提交于 2019-12-02 20:27:38
Alasdair

Use the follow=True option in the client.get() call, and the client will follow the redirect. You can then test that the message is in the context of the view you redirected to.

def test_some_view(self):
    # use follow=True to follow redirect
    response = self.client.get('/some-url/', follow=True)

    # don't really need to check status code because assertRedirects will check it
    self.assertEqual(response.status_code, 200)
    self.assertRedirects(response, '/some-other-url/')

    # get message from context and check that expected text is there
    message = list(response.context.get('messages'))[0]
    self.assertEqual(message.tags, "success")
    self.assertTrue("success text" in message.message)

You can use get_messages() with response.wsgi_request like this (tested in Django 1.10):

from django.contrib.messages import get_messages  
...
def test_view(self):
    response = self.client.get('/some-url/') # you don't need follow=True
    self.assertRedirects(response, '/some-other-url/')
    # each element is an instance of  django.contrib.messages.storage.base.Message
    all_messages = [msg for msg in get_messages(response.wsgi_request)]

    # here's how you test the first message
    self.assertEqual(all_messages[0].tags, "success")
    self.assertEqual(all_messages[0].message, "you have done well")

If your views are redirecting and you use follow=true in your request to the test client the above doesn't work. I ended up writing a helper function to get the first (and in my case, only) message sent with the response.

@classmethod
def getmessage(cls, response):
    """Helper method to return message from response """
    for c in response.context:
        message = [m for m in c.get('messages')][0]
        if message:
            return message

You include this within your test class and use it like this:

message = self.getmessage(response)

Where response is what you get back from a get or post to a Client.

This is a little fragile but hopefully it saves someone else some time.

I had the same problem when using a 3rd party app.

If you want to get the messages from a view that returns an HttpResponseRedict (from which you can't access the context) from within another view, you can use get_messages(request)

from django.contrib.messages import get_messages  

storage = get_messages(request)  
for message in storage:  
    do_something_with_the_message(message)  

This clears the message storage though, so if you want to access the messages from a template later on, add:

storage.used = False

Alternative method mocking messages (doesn't need to follow redirect):

from mock import ANY, patch
from django.contrib import messages

@patch('myapp.views.messages.add_message')
def test_some_view(self, mock_add_message):
    r = self.client.get('/some-url/')
    mock_add_message.assert_called_once_with(ANY, messages.ERROR, 'Expected message.')  # or assert_called_with, assert_has_calls...
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!