![](/img/trans.png)
[英]How can I unit test django messages… with a HTTPResponseRedirect?
[英]How can I unit test django messages?
在我的 django 應用程序中,我試圖編寫一個單元測試來執行一個操作,然后檢查響應中的消息。
據我所知,沒有好的方法可以做到這一點。
我正在使用 CookieStorage 存儲方法,我想做類似下面的事情:
response = self.client.post('/do-something/', follow=True)
self.assertEquals(response.context['messages'][0], "fail.")
問題是,我得到的只是一個
print response.context['messages']
<django.contrib.messages.storage.cookie.CookieStorage object at 0x3c55250>
我怎樣才能把它變成有用的東西,還是我做錯了?
謝謝,丹尼爾
我找到了一個非常簡單的方法:
response = self.client.post('/foo/')
messages = list(response.context['messages'])
self.assertEqual(len(messages), 1)
self.assertEqual(str(messages[0]), 'my message')
如果您需要檢查沒有上下文的響應中的消息,您可以使用以下命令:
from django.contrib.messages import get_messages
messages = list(get_messages(response.wsgi_request))
self.assertEqual(len(messages), 1)
self.assertEqual(str(messages[0]), 'my message')
回退存儲不支持索引,但它是可迭代的。
在模板之外,您可以使用 get_messages()
所以,你可以這樣寫:
from django.contrib.messages import get_messages
[...]
messages = [m.message for m in get_messages(response.wsgi_request)]
self.assertIn('My message', messages)
這對我有用(顯示所有消息):
print [m.message for m in list(response.context['messages'])]
這里還有一些我在從 Django 的 TestCase 繼承的測試類中使用的實用方法。 如果您希望將它們作為函數使用,請刪除self
參數並將self.fail()
替換為raise
。
def assert_message_count(self, response, expect_num):
"""
Asserts that exactly the given number of messages have been sent.
"""
actual_num = len(response.context['messages'])
if actual_num != expect_num:
self.fail('Message count was %d, expected %d' %
(actual_num, expect_num))
def assert_message_contains(self, response, text, level=None):
"""
Asserts that there is exactly one message containing the given text.
"""
messages = response.context['messages']
matches = [m for m in messages if text in m.message]
if len(matches) == 1:
msg = matches[0]
if level is not None and msg.level != level:
self.fail('There was one matching message but with different'
'level: %s != %s' % (msg.level, level))
return
elif len(matches) == 0:
messages_str = ", ".join('"%s"' % m for m in messages)
self.fail('No message contained text "%s", messages were: %s' %
(text, messages_str))
else:
self.fail('Multiple messages contained text "%s": %s' %
(text, ", ".join(('"%s"' % m) for m in matches)))
def assert_message_not_contains(self, response, text):
""" Assert that no message contains the given text. """
messages = response.context['messages']
matches = [m for m in messages if text in m.message]
if len(matches) > 0:
self.fail('Message(s) contained text "%s": %s' %
(text, ", ".join(('"%s"' % m) for m in matches)))
我原來的答案是在 django 還是 1.1 左右的時候寫的。 這個答案不再相關。 請參閱@daveoncode 的答案以獲得更好的解決方案。
我做了一個實驗來測試這個。 我將我的一個項目中的MESSAGE_STORAGE
設置更改為'django.contrib.messages.storage.cookie.CookieStorage'
並執行了我編寫的用於檢查消息的測試。 有效。
與您所做的主要區別在於我檢索消息的方式。 見下文:
def test_message_sending(self):
data = dict(...)
response = self.client.post(reverse('my_view'), data)
messages = self.user.get_and_delete_messages()
self.assertTrue(messages)
self.assertEqual('Hey there!', messages[0])
這可能值得一試。
我創建了一個 python class 來簡化消息測試:
class TestMessageCase(TestCase):
""" class inherited from TestCase to add a function to test messages response """
def assertMessageContains(self, response, messages_list, debug=False):
"""
Function to test messages returned by the response view
:param response: The response of the view
:param messages_list: An ordered list of messages to test
:type messages_list: list of string
:param debug: Show all response messages
:type debug: bool
"""
response_messages = list(response.context['messages'])
if debug:
print(
" ---------------------------------------------------------------------\n",
"| DEBUG MESSAGES RETURNED BY THE RESPONSE |\n",
"---------------------------------------------------------------------"
)
for i in range(len(response_messages)):
print(f"Message n°{i + 1} :\n{response_messages[i]}\n\n")
print(
" ---------------------------------------------------------------------\n",
"| END DEBUG |\n",
"---------------------------------------------------------------------"
)
self.assertEqual(len(response_messages), len(messages_list))
for i in range(len(response_messages)):
self.assertEqual(str(response_messages[i]), messages_list[i])
在測試 function 中:
response = self.client.post('/foo/')
self.assertMessageContains(response, ["Foo"])
僵局的簡單版本:
class TestCaseMessagesMixture(object):
def assertMessageCount(self, response, expect_num):
"""
Asserts that exactly the given number of messages have been sent.
"""
actual_num = len(response.context['messages'])
if actual_num != expect_num:
self.fail('Message count was %d, expected %d' %
(actual_num, expect_num)
)
def assertMessageEqual(self, response, text):
"""
Asserts that the response includes the message text.
"""
messages = [m.message for m in response.context['messages']]
if text not in messages:
self.fail(
'No message with text "%s", messages were: %s' %
(text, messages)
)
def assertMessageNotEqual(self, response, text):
"""
Asserts that the response does not include the message text.
"""
messages = [m.message for m in response.context['messages']]
if text in messages:
self.fail(
'Message with text "%s" found, messages were: %s' %
(text, messages)
)
用於驗證響應消息計數和內容的測試助手
def get_response_messages(self, response):
from django.contrib.messages import get_messages
return list(get_messages(response.wsgi_request))
def check_response_messages(self, response, message_index=None, message_value=None, exp_count=None):
messages = self.get_response_messages(response)
if exp_count is not None:
self.assertEqual(len(messages), exp_count)
if message_index is not None:
message = messages[message_index]
self.assertIn(message_value, str(message))
可以這樣使用
message_value = "You can not switch to another type of account"
self.check_response_messages(response, exp_count=1, message_index=0, message_value=message_value)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.