Fully-Faltoo blog by Pratyush

Bio Twitter Screener

5th Jan. 2021

Snapshot testing in Django


One of the features I loved when using React was snapshot testing. I adopted some of it for Django.


I use snapshot testing mostly for emails. I also use it for standalone templates like invoices.


The function saves the output (eg html) in test files. It then checks if the output has changed.


The advantage is that it works great with version control. Plus it provides a visual update.


So if a test fails, it opens the new version. And we can do a git diff to see actual change in output.

class SnapshotChanged(Exception):
    pass


def compare_snapshot(html, save_path):
    existing = ""
    if os.path.isfile(save_path):
        with io.open(save_path, "r", encoding="utf8") as tmp:
            existing = tmp.read()
    if existing == html:
        return True
    with open(save_path, "wb") as tmp:
        if isinstance(html, str):
            tmp.write(html.encode("utf8", errors="ignore"))
        else:
            # html response from django is in bytes
            tmp.write(html)
    abs_path = "file://{}".format(os.path.abspath(save_path))
    webbrowser.open(abs_path)
    raise SnapshotChanged("Snapshot has been updated")

Now we can use it like this:

class RenderingTestCases(TestCase):
    def test_outlook(self):
        # Campaign with a primary button
        campaign = CampaignFactory(content=OUTLOOK_MAIL)
        UserFactory(id=1, email="foo@bar.com", is_email_verified=True)
        users = UserAccount.objects.all()

        campaign.send(users=users)

        email = mail.outbox[0]
        compare_snapshot(
            email.alternatives[0][0], "campaign/test_files/outlook.html"
        )


Comments