Skip to main content

Capture and make assertions on transaction.on_commit() callbacks.

Project description

https://img.shields.io/github/workflow/status/adamchainz/django-capture-on-commit-callbacks/CI/main?style=for-the-badge https://img.shields.io/codecov/c/github/adamchainz/django-capture-on-commit-callbacks/main?style=for-the-badge https://img.shields.io/pypi/v/django-capture-on-commit-callbacks.svg?style=for-the-badge https://img.shields.io/badge/code%20style-black-000000.svg?style=for-the-badge pre-commit

Capture and make assertions on transaction.on_commit() callbacks. This allows you to write your tests with the TestCase, rather than needing the slower TransactionTestCase to actually commit the transactions.

This package was made as a first pass for Django PR #12944, which is a solution for Ticket #30457 “on_commit should be triggered in a TestCase”. The PR has been merged to Django and has been released in version 3.2, so this package can now be considered a backport.

Read more in my blog post The Fast Way to Test Django transaction.on_commit() Callbacks.

Installation

Use pip:

python -m pip install django-capture-on-commit-callbacks

Requirements

Python 3.6 to 3.9 supported.

Django 2.2 to 3.2 supported.

Note: This package is not needed on Django 3.2+ and a system check will trigger an error on such versions.


Are your tests slow? Check out my book Speed Up Your Django Tests which covers loads of best practices so you can write faster, more accurate tests.


API

capture_on_commit_callbacks(*, using="default", execute=False)

Acts as a context manager that captures on_commit callbacks for the given database connection. It returns a list that contains, on exit of the context, the captured callback functions. From this list you can make assertions on the callbacks or call them to invoke their side effects, emulating a commit.

All arguments must be passed as keyword arguments.

using is the alias of the database connection to capture callbacks for.

execute specifies whether to call all the callbacks automatically as the context manager exits, if no exception has been raised.

For example, you can test a commit hook that sends an email like so:

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


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

        self.assertEqual(response.status_code, 200)

        self.assertEqual(len(callbacks), 1)
        # Execute the callback
        callbacks[0]()

        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, "Contact Form")
        self.assertEqual(mail.outbox[0].body, "I like your site")

The same test can be written a bit more succinctly with execute=True:

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


class ContactTests(TestCase):
    def test_post(self):
        with capture_on_commit_callbacks(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")

TestCaseMixin

A mixin class to be added to your custom TestCase subclass. It adds one method, captureOnCommitCallbacks() that aliases capture_on_commit_callbacks(), to match the camelCase style of unittest assertions.

You can add to your custom TestCase classes like so:

from django import test
from django_capture_on_commit_callbacks import TestCaseMixin


class TestCase(TestCaseMixin, test.TestCase):
    pass

You could then rewrite the above tests with your custom TestCase class like so:

from django.core import mail
from example.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")

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

Built Distribution

File details

Details for the file django-capture-on-commit-callbacks-1.7.0.tar.gz.

File metadata

  • Download URL: django-capture-on-commit-callbacks-1.7.0.tar.gz
  • Upload date:
  • Size: 6.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.2 CPython/3.9.7

File hashes

Hashes for django-capture-on-commit-callbacks-1.7.0.tar.gz
Algorithm Hash digest
SHA256 12938d5838c3b9908f6187808f728c20be40b1e748b0101417665d14a3fd58cb
MD5 8fd25fd0ccdcaf140837b2102ec5dad5
BLAKE2b-256 b5de1a5eea7b29319981bd829e47343f3b3df8413693beba5c511c4c0698231d

See more details on using hashes here.

File details

Details for the file django_capture_on_commit_callbacks-1.7.0-py3-none-any.whl.

File metadata

  • Download URL: django_capture_on_commit_callbacks-1.7.0-py3-none-any.whl
  • Upload date:
  • Size: 5.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.2 CPython/3.9.7

File hashes

Hashes for django_capture_on_commit_callbacks-1.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ec1466e26340029398f7f7469ee04e2cc40f32a119d91fa6513e9230dc59909c
MD5 6fd6d2632094bcc5717421419321ff6a
BLAKE2b-256 d431f653dbb528342549afc8f51fd71f7d78940dfeb3ec29c41ea7db67d492aa

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page