Eudemonix
Eudemonix

Reputation: 1

Problem with testing Messages in Django 5 CreateView

I am writing unit tests of ebook catalog applications in Django 5. The book creation page uses the built-in CreateView. The class code looks like this:

class BookCreate(SuccessMessageMixin, PermissionRequiredMixin, CreateView):

    model = Book
    fields = ['title', 'author', 'genre', 'publisher', 'pages', 'cover', 'summary']

    template_name = 'books/add_book.html'
    permission_required = 'catalog.add_book'
    permission_denied_message = 'Not enough permissions to add a book'

    success_message = 'Book successfully added'
    success_url = reverse_lazy('add-book')

It works as follows: the user fills in the book data, clicks the submit button, then the page is redirected to the same page, plus the page displays the message specified in the success_message attribute of the class

For testing, I use the MessagesTestMixin as described in the Django documentation. Here is the unit test code:

class TestBookCreateView(MessagesTestMixin, TestCase):

    @classmethod
    def setUpTestData(cls):
        cls.test_user = User.objects.create_user(
            email='[email protected]',
            username='John',
            password='Fiesta123'
        )
        cls.add_book_permission = Permission.objects.get(codename='add_book')


    def setUp(self):
        login = self.client.login(username='Ivan', password='Fiesta123')
        self.test_user.user_permissions.set([self.add_book_permission])

    def test_if_view_success_message_attached(self):

        author = Author.objects.create(
            first_name='Charles',
            last_name='Dickens'
        )

        genre = Genre.objects.create(
            genre='Novel'
        )

        book_data = {
            'title': 'Great Expectations',
            'author': author,
            'genre': genre
        }

        response = self.client.post(reverse('add-book'), data=book_data, follow=True)
        self.assertMessages(response, 'Book successfully added')

The test fails, I see an empty list in the results instead of a message. However, in the application, the message is successfully passed to the page template and I see it on the page after the book is created. Message storage backend in settings.py is not explicitly set, so the app using storage.fallback.FallbackStorage provided by default.

So what could be a problem in this case and in general what are the good practices for messages testing in Django CBV?

Upvotes: 0

Views: 35

Answers (1)

Steve
Steve

Reputation: 7108

Look at the definition of MessagesTestMixin.

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)

It just compares the messages using either assertEqual (equal contents, same order) or assertCountEqual (equal contents, but in any order) to whatever you pass in. The messages are stored as a list of django.contrib.messages.storage.base.Message instances, so for the assertion to be true, you have to construct an equivalent list.

from django.contrib import messages
from django.contrib.messages.test import MessagesTestMixin

class TestBookCreateView(MessagesTestMixin, TestCase):
    def test_if_view_success_message_attached(self):
        # ...
        self.assertMessages(response, [
            messages.Message(messages.SUCCESS, 'Book successfully added'),
        ])

(I've assumed your message was a success message. The possible constants are DEBUG, INFO, SUCCESS, WARNING, and ERROR.)

Upvotes: 0

Related Questions