aisbaa
aisbaa

Reputation: 10633

Django how to test if message is sent

I want to test if message is sent to user after submit. I'm using django.contrib.messages. Everything seems to be working during manual testing (runserver), but in unit test I don't get messages.

Code that stores message:

messages.success(request, _('Internationalized evil message.'))

Code that should test message:

from django.contrib.messages.api import get_messages

...

def test_message_should_sent_to_user(self):
    """After successful phone number submit, message should be displayed."""
    response = self.client.post(
        reverse('evil.views.evil_data_submit'), self.valid_data)
    messages = get_messages(response.request)
    self.assertNotEqual(len(messages), 0)

It looks like that no middleware is called during test client post method call.


Update after @Tisho answer

Messages should be found in response.context, even my guts say that it should work, but it doesn't. I've placed import pdb; pdb.set_trace() in django/contrib/messages/context_processors.py to see if its called during test client.post, its not.

I've double checked TEMPLATE_CONTEXT_PROCESSORS, MIDDLEWARE_CLASSES and INSTALLED_APPS - probably tomorrow I'll discover that I missed something.


Important detail

Forgot to mention that in case of successful submit view returns HttpResponseRedirect therefore response.context is empty.


Solution

View returns redirect (which has no context data), to solve that we can pass follow=True to client.post method (method suggested by @Tisho).

Upvotes: 5

Views: 2981

Answers (2)

Tisho
Tisho

Reputation: 8482

During unit tests, the message could be found in

response = self.client.post(
    reverse('evil.views.evil_data_submit'), self.valid_data)
messages = response.context['messages']

If your view returns a redirect, response.context will be empty unless you pass follow=True, like so:

response = self.client.post(
    reverse('evil.views.evil_data_submit'),
    self.valid_data,
    follow=True)

Upvotes: 7

Oduvan
Oduvan

Reputation: 2757

The best way I found is by using mock

http://www.voidspace.org.uk/python/mock/patch.html#patch-methods-start-and-stop

class SimpleCommentTestDirect(TestCase):

def setUp(self):
    self._patcher1 = patch('django.contrib.messages.error')
    self.mock_error = self._patcher1.start()

def tearDown(self):
    self._patcher1.stop()

def test_error_message(self):
    self.client.get('/vote/direct/unknownapp/comment/1/up/')
    self.assertEqual(self.mock_error.call_args[0][1], 'Wrong request. Model.')

BTW: There are also should be a way to get request by using mock. And by using request object get message from django.contrib.messages.get_messages

Upvotes: 2

Related Questions