Pārlūkot izejas kodu

Fixed #34730 -- Added django.contrib.messages.test.MessagesTestMixin.assertMessages().

François Freitag 1 gadu atpakaļ
vecāks
revīzija
cafe7266ee

+ 8 - 0
django/contrib/messages/test.py

@@ -0,0 +1,8 @@
+from .api import get_messages
+
+
+class MessagesTestMixin:
+    def assertMessages(self, response, expected_messages, *, ordered=True):
+        request_messages = list(get_messages(response.wsgi_request))
+        assertion = self.assertEqual if ordered else self.assertCountEqual
+        assertion(request_messages, expected_messages)

+ 33 - 0
docs/ref/contrib/messages.txt

@@ -452,3 +452,36 @@ the session cookie settings:
 * :setting:`SESSION_COOKIE_DOMAIN`
 * :setting:`SESSION_COOKIE_SECURE`
 * :setting:`SESSION_COOKIE_HTTPONLY`
+
+Testing
+=======
+
+.. versionadded:: 5.0
+
+This module offers a tailored test assertion method, for testing messages
+attached to an :class:`~.HttpResponse`.
+
+To benefit from this assertion, add ``MessagesTestMixin`` to the class
+hierarchy::
+
+    from django.contrib.messages.test import MessagesTestMixin
+    from django.test import TestCase
+
+
+    class MsgTestCase(MessagesTestMixin, TestCase):
+        pass
+
+Then, inherit from the ``MsgTestCase`` in your tests.
+
+.. module:: django.contrib.messages.test
+
+.. method:: MessagesTestMixin.assertMessages(response, expected_messages, ordered=True)
+
+    Asserts that :mod:`~django.contrib.messages` added to the :class:`response
+    <django.http.HttpResponse>` matches ``expected_messages``.
+
+    ``expected_messages`` is a list of
+    :class:`~django.contrib.messages.Message` objects.
+
+    By default, the comparison is ordering dependent. You can disable this by
+    setting the ``ordered`` argument to ``False``.

+ 3 - 1
docs/releases/5.0.txt

@@ -247,7 +247,9 @@ Minor features
 :mod:`django.contrib.messages`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-* ...
+* The new :meth:`.MessagesTestMixin.assertMessages` assertion method allows
+  testing :mod:`~django.contrib.messages` added to a
+  :class:`response <django.http.HttpResponse>`.
 
 :mod:`django.contrib.postgres`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ 3 - 12
tests/messages_tests/test_api.py

@@ -1,17 +1,7 @@
 from django.contrib import messages
 from django.test import RequestFactory, SimpleTestCase
 
-
-class DummyStorage:
-    """
-    dummy message-store to test the api methods
-    """
-
-    def __init__(self):
-        self.store = []
-
-    def add(self, level, message, extra_tags=""):
-        self.store.append(message)
+from .utils import DummyStorage
 
 
 class ApiTests(SimpleTestCase):
@@ -25,7 +15,8 @@ class ApiTests(SimpleTestCase):
         msg = "some message"
         self.request._messages = self.storage
         messages.add_message(self.request, messages.DEBUG, msg)
-        self.assertIn(msg, self.storage.store)
+        [message] = self.storage.store
+        self.assertEqual(msg, message.message)
 
     def test_request_is_none(self):
         msg = "add_message() argument must be an HttpRequest object, not 'NoneType'."

+ 100 - 2
tests/messages_tests/tests.py

@@ -1,8 +1,11 @@
 from unittest import mock
 
-from django.contrib.messages import Message, constants
+from django.contrib.messages import Message, add_message, constants
 from django.contrib.messages.storage import base
-from django.test import SimpleTestCase, override_settings
+from django.contrib.messages.test import MessagesTestMixin
+from django.test import RequestFactory, SimpleTestCase, override_settings
+
+from .utils import DummyStorage
 
 
 class MessageTests(SimpleTestCase):
@@ -59,3 +62,98 @@ class TestLevelTags(SimpleTestCase):
     @override_settings(MESSAGE_TAGS=message_tags)
     def test_override_settings_level_tags(self):
         self.assertEqual(base.LEVEL_TAGS, self.message_tags)
+
+
+class FakeResponse:
+    def __init__(self):
+        request = RequestFactory().get("/")
+        request._messages = DummyStorage()
+        self.wsgi_request = request
+
+
+class AssertMessagesTest(MessagesTestMixin, SimpleTestCase):
+    def test_assertion(self):
+        response = FakeResponse()
+        add_message(response.wsgi_request, constants.DEBUG, "DEBUG message.")
+        add_message(response.wsgi_request, constants.INFO, "INFO message.")
+        add_message(response.wsgi_request, constants.SUCCESS, "SUCCESS message.")
+        add_message(response.wsgi_request, constants.WARNING, "WARNING message.")
+        add_message(response.wsgi_request, constants.ERROR, "ERROR message.")
+        self.assertMessages(
+            response,
+            [
+                Message(constants.DEBUG, "DEBUG message."),
+                Message(constants.INFO, "INFO message."),
+                Message(constants.SUCCESS, "SUCCESS message."),
+                Message(constants.WARNING, "WARNING message."),
+                Message(constants.ERROR, "ERROR message."),
+            ],
+        )
+
+    def test_with_tags(self):
+        response = FakeResponse()
+        add_message(
+            response.wsgi_request,
+            constants.INFO,
+            "INFO message.",
+            extra_tags="extra-info",
+        )
+        add_message(
+            response.wsgi_request,
+            constants.SUCCESS,
+            "SUCCESS message.",
+            extra_tags="extra-success",
+        )
+        add_message(
+            response.wsgi_request,
+            constants.WARNING,
+            "WARNING message.",
+            extra_tags="extra-warning",
+        )
+        add_message(
+            response.wsgi_request,
+            constants.ERROR,
+            "ERROR message.",
+            extra_tags="extra-error",
+        )
+        self.assertMessages(
+            response,
+            [
+                Message(constants.INFO, "INFO message.", "extra-info"),
+                Message(constants.SUCCESS, "SUCCESS message.", "extra-success"),
+                Message(constants.WARNING, "WARNING message.", "extra-warning"),
+                Message(constants.ERROR, "ERROR message.", "extra-error"),
+            ],
+        )
+
+    @override_settings(MESSAGE_TAGS={42: "CUSTOM"})
+    def test_custom_levelname(self):
+        response = FakeResponse()
+        add_message(response.wsgi_request, 42, "CUSTOM message.")
+        self.assertMessages(response, [Message(42, "CUSTOM message.")])
+
+    def test_ordered(self):
+        response = FakeResponse()
+        add_message(response.wsgi_request, constants.INFO, "First message.")
+        add_message(response.wsgi_request, constants.WARNING, "Second message.")
+        expected_messages = [
+            Message(constants.WARNING, "Second message."),
+            Message(constants.INFO, "First message."),
+        ]
+        self.assertMessages(response, expected_messages, ordered=False)
+        with self.assertRaisesMessage(AssertionError, "Lists differ: "):
+            self.assertMessages(response, expected_messages)
+
+    def test_mismatching_length(self):
+        response = FakeResponse()
+        add_message(response.wsgi_request, constants.INFO, "INFO message.")
+        msg = (
+            "Lists differ: [Message(level=20, message='INFO message.')] != []\n\n"
+            "First list contains 1 additional elements.\n"
+            "First extra element 0:\n"
+            "Message(level=20, message='INFO message.')\n\n"
+            "- [Message(level=20, message='INFO message.')]\n"
+            "+ []"
+        )
+        with self.assertRaisesMessage(AssertionError, msg):
+            self.assertMessages(response, [])

+ 14 - 0
tests/messages_tests/utils.py

@@ -0,0 +1,14 @@
+from django.contrib.messages import Message
+
+
+class DummyStorage:
+    """Dummy message-store to test the API methods."""
+
+    def __init__(self):
+        self.store = []
+
+    def add(self, level, message, extra_tags=""):
+        self.store.append(Message(level, message, extra_tags))
+
+    def __iter__(self):
+        return iter(self.store)