Django Testing — проверка сообщений на наличие представления, которое перенаправляет

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

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 не содержит словаря context, содержащего messages, так как это представление использует перенаправление. Для представлений, отображающих шаблоны, мы можем получить доступ к списку сообщений, используя messages = response.context.get('messages'). Как мы можем получить доступ messages к представлению, которое перенаправляет?


person Amyth    schedule 22.04.2013    source источник
comment
Не уверен, что это будет соответствовать вашим потребностям, но вы можете передать переменные get, чтобы определить, что произошло: redirect(reverse(some_other_view) + '?user_added=true')   -  person Aamir Adnan    schedule 22.04.2013
comment
На самом деле я уже тестирую условие, используемое в представлении в моем тесте. Здесь я говорю о явном тестировании отправленного сообщения.   -  person Amyth    schedule 22.04.2013


Ответы (5)


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

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)
person Alasdair    schedule 22.04.2013
comment
Спасибо, это сработало. Однако использование follow=True изменяет ожидаемый код перенаправления с 302 на 200, поскольку он следует за перенаправленным представлением. - person Amyth; 22.04.2013
comment
Да, после перенаправления означает, что ответ имеет код состояния 200. " rel="nofollow noreferrer">assertRedirects, который можно использовать для проверки перенаправления. - person Alasdair; 22.04.2013
comment
да, это то, что я использую сейчас :) - person Amyth; 22.04.2013
comment
Это также работает для client.post(), чтобы добавить follow=True - person Aaron Lelevier; 28.05.2014
comment
Вы не можете получить доступ к элементам в сообщениях напрямую с помощью messages[0], вы должны преобразовать их в список или кортеж — list(messages) - person bbrik; 25.11.2015
comment
@bbrik ответ обновлен, извините, я не увидел ваш комментарий раньше. - person Alasdair; 30.06.2016

Вы можете использовать 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")
person Florentin    schedule 15.02.2017
comment
Это сработало для меня, тогда как метод Аласдера не показывал никаких сообщений. У меня Джанго 1.11. - person Serge Mosin; 18.07.2017

Если ваши представления перенаправляют и вы используете 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.

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

person turtlemonvh    schedule 12.09.2013
comment
Вам не нужно это понимание списка, просто используйте список (сообщения) или кортеж (сообщения). - person bbrik; 25.11.2015

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

Если вы хотите получать сообщения из представления, которое возвращает 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
person kerryz    schedule 24.06.2014

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

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...
person laffuste    schedule 23.05.2017