2013-04-22 1 views
19

Я писал тесты для одного из своих приложений django и давно искал эту проблему. У меня есть представление, которое отправляет сообщения с использованием django.contrib.messages для разных случаев. Вид выглядит примерно так:Django Testing - проверить сообщения для просмотра, которое перенаправляет

from django.contrib import messages 
from django.shortcuts import redirect 

import custom_messages 

def some_view(request): 
    """ This is a sample view for testing purposes. 
    """ 

    some_condition = models.SomeModel.objects.get_or_none(
     condition=some_condition) 
    if some_condition: 
     messages.success(request, custom_message.SUCCESS) 
    else: 
     messages.error(request, custom_message.ERROR) 
    redirect(some_other_view) 

Теперь, при тестировании этого ответа вида client.get «s не содержит context словаря, который содержит messages как это вид использует редирект. Для представлений, отображающих шаблоны, мы можем получить доступ к списку сообщений, используя messages = response.context.get('messages'). Как мы можем получить доступ messages для просмотра, которое перенаправляет?

+0

Не уверен, если это будет соответствовать вашим потребностям, но вы можете передать получить переменные, чтобы определить, что произошло: 'перенаправлять (обратный (some_other_view) + '? user_added = true') ' –

+0

Я уже тестирую условие, которое используется в представлении в моем тесте. Здесь я говорю о явном тестировании отправленного сообщения. – Amyth

ответ

31

Используйте опцию follow=True в вызове client.get(), и клиент выполнит перенаправление. Затем вы можете проверить, что сообщение находится в контексте просматриваемого вами вида.

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) 
+0

Спасибо, что сработало. Хотя использование 'follow = True' изменяет ожидаемый код перенаправления с' 302' на '200', поскольку он следует за перенаправленным представлением. – Amyth

+0

Да, после перенаправления означает, что ответ имеет код состояния 200. Существует ['assertRedirects'] (https://docs.djangoproject.com/en/1.5/topics/testing/overview/#django.test.TestCase ,assertRedirects), который вы можете использовать для проверки перенаправления. – Alasdair

+0

yup, вот что я использую сейчас :) – Amyth

1

Если ваши взгляды перенаправлять и использовать follow=true в запросе на тестовом клиенте выше не работает. Я закончил писать вспомогательную функцию, чтобы получить первое (и в моем случае только) сообщение, отправленное с ответом.

@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 

Вы включаете это в тестовом классе и использовать его как это:

message = self.getmessage(response) 

Где response что вы получаете назад от get или post к Client.

Это немного хрупкий, но, надеюсь, это сэкономит кому-то еще некоторое время.

+2

Вам не нужно это понимание списка, просто используйте список (сообщения) или кортеж (сообщения). – bbrik

1

У меня была такая же проблема при использовании стороннего приложения.

Если вы хотите получать сообщения из тем, что возвращает HttpResponseRedict (от которого вы не можете получить доступ к контексту) из другой точки зрения, вы можете использовать get_messages(request)

from django.contrib.messages import get_messages 

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

Это очищает хранилище сообщений хотя, так что если вы хотите получить доступ к сообщениям из шаблона позже, добавьте:

storage.used = False 
4

вы можете использовать get_messages() с response.wsgi_request, как это (проверено в 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") 
+0

Это работало для меня, тогда как метод Аласдайра не показывал никаких сообщений. Я на Django 1.11. –

0

Альтернативных метод насмешливых сообщений (не нужно следовать перенаправлять):

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...