Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test a Django on_commit hook without clearing the database?

The on_commit function has been added to Django 1.9 to be able to trigger an action (e.g. a Celery task) after the current transaction has committed.

They mention later in the docs that one should use TransactionTestCase to test features that rely on that function. However, unlike TestCase (which uses transactions and rolls them back), TransactionTestCase empties the whole database after each test.

Unfortunately, I have data migrations that preload some useful data inside the database, which means that subsequent tests do not work anymore after the first test clears the database.

I ended up resorting to a dirty trick by mocking on_commit :

with mock.patch.object(django.db.transaction, 'on_commit', lambda t: t()):
    test_something()

Is there a better way?

like image 792
F.X. Avatar asked Mar 03 '17 17:03

F.X.


1 Answers

Starting with version 3.2 Django has a build-in way to test the on_comit hook. Example:

from django.core import mail
from django.test import TestCase


class ContactTests(TestCase):
    def test_post(self):
        with self.captureOnCommitCallbacks(execute=True) as callbacks:
            response = self.client.post(
                '/contact/',
                {'message': 'I like your site'},
            )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(callbacks), 1)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, 'Contact Form')
        self.assertEqual(mail.outbox[0].body, 'I like your site')

Here is the official documentation: https://docs.djangoproject.com/en/4.0/topics/testing/tools/#django.test.TestCase.captureOnCommitCallbacks

like image 194
Slava Avatar answered Oct 24 '22 15:10

Slava