Search code examples
pythondjangounit-testingdjango-messages

How can I unit test django messages... with a HTTPResponseRedirect?


Just like this question... but harder.

I have a view that redirects a user, and uses the Django messages framework to send them to the right page, and adds a message with code like that below:

def new_comment(request,pid):
    post = get_object_or_404(DiscussionPost,pk=pid)
    if post.closed:
        messages.error(request, _('This post is closed. Your comment was not added.'))
        return HttpResponseRedirect(reverse("discussionsPost",args=[post.pk]))

Now this works well for a user, but when testing the messages aren't available.

In the unit test I do:

    response = self.client.post(reverse('aristotle:discussionsPostNewComment',args=[p1.id]),
        {'body':"Post is closed, so I can NOT comment."}
    )
    #the below assertion passes
    self.assertRedirects(response,reverse('aristotle:discussionsPost',args=[p1.id]))

    print response
    print response.context['messages']       

And the first print gives:

Vary: Accept-Language, Cookie
X-Frame-Options: SAMEORIGIN
Content-Type: text/html; charset=utf-8
Location: http://testserver/discussions/post/1
Content-Language: en

With the second failing with the error:

Traceback (most recent call last):
  File "/home/ubuntu/workspace/aristotle_mdr/tests/main/test_discussions.py", line 393, in test_post_to_closed_discussion
    print response.context['messages']
TypeError: 'NoneType' object has no attribute '__getitem__'

Plus there its not possible to use messages.get_messages as there is no request item that can be used.

Since, there is no context dictionary in HTTPResponseRedirect, how can I check whether the message was sent properly?


Solution

  • If you want to test the response after the redirect, then you need to tell the Django test client to "follow" the redirect chain, via the follow argument. As stated in the Django documentation:

    If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes.

    So your test post would need to look something like:

        response = self.client.post(
            reverse('aristotle:discussionsPostNewComment', args=[p1.id]),
            {'body':"Post is closed, so I can NOT comment."},
            follow=True
        )