Тесты Django не выводят Сообщения при рендеринге шаблона
Я не могу создать модульный тест для проверки правильности отображения сообщений в моем шаблоне. В соответствии с моим шаблоном, я не получаю никакого вывода, где сообщения должны быть перечислены.
Я использую pytest 6.2.5 и Django 3.1.13, если это поможет. Вот мой тестовый код:
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
Мой блок сообщений в шаблоне (base.html) прямолинеен (и действительно работает в представлениях, которые отправляют сообщения):
{% if messages %}
<div>
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
</div>
{% endif %}
Я могу видеть через отладку, что прежде чем вы дойдете до рендеринга ответа, сообщение "Hello, world!" отмечается должным образом в запросе через промежуточное ПО Session/Message, оно просто не рендерится в ответе.
Есть идеи, что я упускаю? Нужно ли мне сделать что-то с контекстным препроцессором перед рендерингом содержимого?
Заранее спасибо за любой совет!
Возможно, существует более простой метод, но для меня хитрость заключалась в том, чтобы явно включить сообщения в контекст представления.
Вот как мне удалось заставить представление правильно отображать сообщения. Обратите внимание, что я использую pytest, со стандартным RequestFactory fixture. Должно быть довольно тривиально преобразовать этот код в парадигму unittest
.
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