1
0
mirror of https://github.com/django/django.git synced 2025-10-24 14:16:09 +00:00

Fixed #30457 -- Added TestCase.captureOnCommitCallbacks().

This commit is contained in:
Adam Johnson
2020-05-20 11:04:36 +01:00
committed by Mariusz Felisiak
parent ca6c5e5fc2
commit e906ff6fca
5 changed files with 137 additions and 4 deletions

View File

@@ -276,6 +276,11 @@ Tests
* :class:`~django.test.Client` now preserves the request query string when
following 307 and 308 redirects.
* The new :meth:`.TestCase.captureOnCommitCallbacks` method captures callback
functions passed to :func:`transaction.on_commit()
<django.db.transaction.on_commit>` in a list. This allows you to test such
callbacks without using the slower :class:`.TransactionTestCase`.
URLs
~~~~

View File

@@ -394,9 +394,19 @@ Use in tests
Django's :class:`~django.test.TestCase` class wraps each test in a transaction
and rolls back that transaction after each test, in order to provide test
isolation. This means that no transaction is ever actually committed, thus your
:func:`on_commit` callbacks will never be run. If you need to test the results
of an :func:`on_commit` callback, use a
:class:`~django.test.TransactionTestCase` instead.
:func:`on_commit` callbacks will never be run.
You can overcome this limitation by using
:meth:`.TestCase.captureOnCommitCallbacks`. This captures your
:func:`on_commit` callbacks in a list, allowing you to make assertions on them,
or emulate the transaction committing by calling them.
Another way to overcome the limitation is to use
:class:`~django.test.TransactionTestCase` instead of
:class:`~django.test.TestCase`. This will mean your transactions are committed,
and the callbacks will run. However
:class:`~django.test.TransactionTestCase` flushes the database between tests,
which is significantly slower than :class:`~django.test.TestCase`\'s isolation.
Why no rollback hook?
---------------------

View File

@@ -881,6 +881,42 @@ It also provides an additional method:
previous versions of Django these objects were reused and changes made
to them were persisted between test methods.
.. classmethod:: TestCase.captureOnCommitCallbacks(using=DEFAULT_DB_ALIAS, execute=False)
.. versionadded:: 3.2
Returns a context manager that captures :func:`transaction.on_commit()
<django.db.transaction.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.
``using`` is the alias of the database connection to capture callbacks for.
If ``execute`` is ``True``, all the callbacks will be called as the context
manager exits, if no exception occurred. This emulates a commit after the
wrapped block of code.
For 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')
.. _live-test-server:
``LiveServerTestCase``