0

I can't seem to get a unit test to check if Messages are rendering properly in my template. As per my template, I'm not getting any output where the messages should be listed.

I'm using pytest 6.2.5 and Django 3.1.13 if that's helpful. Here is my test code:

import pytest
from django.contrib import messages
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import RequestFactory
from django.views.generic import TemplateView

pytestmark = pytest.mark.django_db

class TestBaseTemplate:
    def test_messages_middleware(self):
        request = RequestFactory().get("/")
        view = TemplateView.as_view(template_name="base.html")

        middleware1 = SessionMiddleware()
        middleware1.process_request(request)
        request.session.save()

        middleware2 = MessageMiddleware()
        middleware2.process_request(request)

        foobar_msg = "Hello, world!"
        messages.info(request, foobar_msg)

        request.session.save()
        response = view(request)

        response.render()
        content = response.content.decode("utf-8")

        # This assert fails
        assert foobar_msg in content 

My message block in the template (base.html) is straight-forward (and does work in views that send messages):

  {% if messages %}
  <div>
    {% for message in messages %}
    <p>{{ message }}</p>
    {% endfor %}
  </div>
  {% endif %}

I can see through debugging that before you get to rendering the response that the "Hello, world!" message is being noted properly in the request via the Session/Message middleware, it's just not being rendered in the response.

Any ideas on what I'm missing? Do I need to do something with a context preprocessor before rendering the content?

Thanks in advance for any advice!

2
  • How about testing your response contain the message? e.g. def test_abc(self): response = self.client.get('/response') message = list(response.context.get('messages'))[0] self.assertEqual(message.tags, ‘tag e.g success’) msg = 'the message’ self.assertTrue(msg in message.message) Commented Nov 23, 2021 at 17:38
  • Yes, it's a good thought, and might end up being the "good enough" solution. Probably trying to be too clever with this, but as I understand it using the Django client tool would be testing a specific URL/view that has messages attached to it (more of an integration test). I was hoping to be a bit more, hmm... abstract with this test? i.e., here is a series of messages I've specified in a test, prove to me the template is rendering properly with it. Commented Nov 23, 2021 at 18:30

1 Answer 1

1

There might be a more straight-forward method, but the trick for me was to explicitly include the messages in the view context.

Here is how I managed to get the view properly rendering messages. Note that I'm using pytest, with a standard RequestFactory fixture. It should be pretty trivial to convert this code to a unittest paradigm.

from typing import Any

import pytest
from django.contrib import messages
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import RequestFactory
from django.views.generic import TemplateView


pytestmark = pytest.mark.django_db


class TestTemplateMessages:
    """Tests for the messages rendering in template."""

    class SampleTemplate(TemplateView):
        """Template for testing."""

        template_name = "frame_with_messages_block.html"

        def __init__(self, **kwargs: Any) -> None:
            """Setup request middleware."""
            super().__init__(**kwargs)
            middleware1 = SessionMiddleware()
            middleware1.process_request(self.request)

            middleware2 = MessageMiddleware()
            middleware2.process_request(self.request)

            self.request.session.save()

        def get_context_data(self, **kwargs: str) -> dict[str, Any]:
            """Add current user to context."""
            context = super().get_context_data(**kwargs)
            context["messages"] = messages.get_messages(self.request)
            return context

    def test_messages_middleware(self, rf: RequestFactory) -> None:
        """Test messages are rendering properly in templates."""
        request = rf.get("/")

        info_message = "Hello, world!"
        error_message = "Hello, error?"
        expected_messages = [info_message, error_message]

        view = self.SampleTemplate(request=request)
        messages.info(request, info_message)
        messages.error(request, error_message)

        # Test messages are part of the request middleware
        actual_messages = [str(m) for m in messages.get_messages(request)]
        assert actual_messages == expected_messages

        # Test messages are present in the response HTML
        response = view.get(request)
        response.render()  # type: ignore
        content = response.content.decode("utf-8")
        for message in expected_messages:
            assert message in content
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.