summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrançois Freitag <mail@franek.fr>2023-06-15 17:16:46 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-09-05 11:55:37 +0200
commitcafe7266ee69f7e017ddbc0d440084ace559b04b (patch)
treeed48113e9c2002d37c1249ad17931e4ca486448f
parent4f0c0e6fa1ce2e4da9407f122d0c1c27c7f8ad83 (diff)
Fixed #34730 -- Added django.contrib.messages.test.MessagesTestMixin.assertMessages().
-rw-r--r--django/contrib/messages/test.py8
-rw-r--r--docs/ref/contrib/messages.txt33
-rw-r--r--docs/releases/5.0.txt4
-rw-r--r--tests/messages_tests/test_api.py15
-rw-r--r--tests/messages_tests/tests.py102
-rw-r--r--tests/messages_tests/utils.py14
6 files changed, 161 insertions, 15 deletions
diff --git a/django/contrib/messages/test.py b/django/contrib/messages/test.py
new file mode 100644
index 0000000000..3a69f54585
--- /dev/null
+++ b/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)
diff --git a/docs/ref/contrib/messages.txt b/docs/ref/contrib/messages.txt
index f5c5621c71..b85f425277 100644
--- a/docs/ref/contrib/messages.txt
+++ b/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``.
diff --git a/docs/releases/5.0.txt b/docs/releases/5.0.txt
index 5a8e44f1fb..5b8abc8498 100644
--- a/docs/releases/5.0.txt
+++ b/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`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/messages_tests/test_api.py b/tests/messages_tests/test_api.py
index 40283d4153..802f5b53ce 100644
--- a/tests/messages_tests/test_api.py
+++ b/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'."
diff --git a/tests/messages_tests/tests.py b/tests/messages_tests/tests.py
index 1ebb6aaba2..4280cb6e3b 100644
--- a/tests/messages_tests/tests.py
+++ b/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, [])
diff --git a/tests/messages_tests/utils.py b/tests/messages_tests/utils.py
new file mode 100644
index 0000000000..f00ea4585b
--- /dev/null
+++ b/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)