【问题标题】:Django Testing - check messages for a view that redirectsDjango 测试 - 检查消息以获取重定向的视图
【发布时间】:2013-04-22 09:03:04
【问题描述】:

我一直在为我的一个 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 的响应不包含包含 messagescontext 字典,因为此视图使用重定向。对于呈现模板的视图,我们可以使用messages = response.context.get('messages') 访问消息列表。我们如何才能访问messages 以获得重定向视图?

【问题讨论】:

  • 不确定这是否符合您的需要,但您可以通过 get 变量来确定发生了什么:redirect(reverse(some_other_view) + '?user_added=true')
  • 我实际上已经在测试我的测试视图中使用的条件。这里我说的是显式测试发送的消息。

标签: django redirect testing messages django-context


【解决方案1】:

client.get() 调用中使用follow=True 选项,客户端将遵循重定向。然后,您可以测试该消息是否在您重定向到的视图的上下文中。

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)

【讨论】:

  • 谢谢,成功了。不过,使用follow=True 会将预期的重定向代码从302 更改为200,因为它遵循重定向视图。
  • 是的,跟随重定向意味着响应的状态码为 200。有一个 assertRedirects 方法可以用来测试重定向。
  • 是的,这就是我现在使用的:)
  • 这也适用于client.post()添加follow=True
  • 不能用messages[0]直接访问messages中的元素,必须将其转换为列表或元组——list(messages)
【解决方案2】:

您可以像这样将 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")

【讨论】:

  • 这对我有用,而 Alasdair 的方法没有显示任何消息。我在 Django 1.11 上。
【解决方案3】:

如果您的视图正在重定向并且您在对测试客户端的请求中使用了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 是您从getpost 返回到Client 的结果。

这有点脆弱,但希望它可以节省其他人一些时间。

【讨论】:

  • 你不需要列表理解,只需使用 list(messages) 或 tuple(messages)。
【解决方案4】:

我在使用 3rd 方应用时遇到了同样的问题。

如果您想从另一个视图中返回 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

【讨论】:

    【解决方案5】:

    模拟消息的替代方法(不需要遵循重定向):

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

    【讨论】:

      猜你喜欢
      • 2019-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-01
      相关资源
      最近更新 更多