Testing comments on a Wagtail page with Factory Boy

This tutorial will test comments that are created on a Wagtail page using the package Django Comments Xtd, using Factory Boy.

July 15, 2020, 2:07 p.m.
Themes: Testing

Our starting point is a commenting functionality and a page testing setup for Wagtail with Factory Boy. As in the earlier tutorials we create a comment factory in /tests/factories.py. Because we also want to save a user with our comments, we start by creating a user factory:

import factory
from userauth.models import CustomUser

class CustomUserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = CustomUser

    username = factory.Sequence(lambda n: 'Username{0}'.format(n))
    password = factory.Sequence(lambda n: 'Password{0}'.format(n))

We automatically generate a username and password because that is the minimum Django expects. Note that in our authentication implementation we use email instead of username, but this is managed by allauth, and since we do not use allauth's signup functionality, we need to take care of this ourselves. Now we are ready to create a comment factory:

from ..models import ArticlePage, CustomComment
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site as DjangoSite

class CustomCommentFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = CustomComment

    content_type = ContentType.objects.get_for_model(ArticlePage)
    site = DjangoSite.objects.get_current()
    page = factory.SubFactory(ArticlePageFactory)
    user = factory.SubFactory(CustomUserFactory)
    comment = factory.Sequence(lambda n: 'Comment {0}'.format(n))

Looking at the model for comments we need three required fields: content_type, site and object_pk. Our comments are going to be on an ArticlePage, so we can retrieve the content type using the Django method get_for_model(). The current site can be retrieved with the Django method get_current(). We rename the Site class to avoid confusion with the Wagtail Site class. The third required field object_pk will be defined when creating the comment instance. page and user are two foreign key relations of the comment, so we use a SubFactory for them. And finally for the comment text itself we generate a text with Sequence.

We can set up a few Wagtail pages just as we have done earlier. Put the following in a file /tests/test_comments.py:

from .factories import HomePageFactory, ArticlePageFactory, ArticleIndexPageFactory
from django.test import TestCase
from wagtail.core.models import Page, Site

class TestComments(TestCase):

    def setUpTestData(cls):
        cls.site = Site.objects.create(is_default_site=True, root_page=Page.get_first_root_node())
        cls.homepage = HomePageFactory()
        cls.articleindexpage = ArticleIndexPageFactory(parent=cls.homepage)
        cls.articlepage1 = ArticlePageFactory(parent=cls.articleindexpage)

Now we add a user and a comment by that user to the setup:

from .factories import CustomUserFactory, CustomCommentFactory

cls.user = CustomUserFactory(email="johndoe@example.com", display_name="John")
cls.customcomment = CustomCommentFactory(object_pk=str(cls.articlepage1.pk), user=cls.user)

The fields for the user are self-explanatory. For the comment, as mention before, now we define the object_pk: we set it to the primary key of the page on which we want the comment. Since Django Comments defines the field as a text field, we convert the primary key first. That completes the setup. The test itself is now very simple. The interesting part of the model to test is the save() method, and since the comment is already created this should have done its work already. So we just check whether the page and the user are save correctly:

def test_custom_comment_gets_saved_correctly(self):
    self.assertEqual(self.customcomment.page.url, self.articlepage1.url)
    self.assertEqual(self.customcomment.user_name, self.user.display_name)

We leave it at that. Checking our coverage with

coverage run --source=cms manage.py test cms.tests
coverage html

tells us that the largest part of our uncovered code is in our streamforms, so that's where we'll go next.

Comment on this article (sign in first or confirm by name and email below)