#30457: on_commit should be triggered in a TestCase
------------------------------------+--------------------------------------
Reporter: Bernhard Mäder | Owner: nobody
Type: New feature | Status: new
Component: Testing framework | Version: master
Severity: Normal | Resolution:
Keywords: on_commit TestCase | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------------+--------------------------------------
Changes (by Simon Charette):
* cc: Simon Charette (added)
* version: 1.11 => master
Comment:
Hi Bernhard,
`on_commit` hooks are not run during `TestCase` because of the transaction
wrapping it performs to ensure data isolation. In short each test is
wrapped in a transaction that is rolled back on teardown
[https://docs.djangoproject.com/en/2.2/topics/testing/tools/#testcase
which is documented]. That means the connection never actually commits the
transaction and thus `on_commit` hooks are never fired. I've previously
discussed changing the behavior to make `on_commit` hook fire on the most
inner `SAVEPOINT` commit to abstract's `TestCase` wrapping but that would
be backward incompatible and wouldn't account for nested
`atomic(savepoint=False)` usages.
The only viable solution we came up with at $DAYJOB is similar to yours.
We added an `immediate_on_commit` context manager to our base `TestCase`
subclass
{{{#!python
@contextmanager
def immediate_on_commit(self, using=None):
"""
Context manager executing transaction.on_commit() hooks immediately as
if the connection was in auto-commit mode. This is required when
using a subclass of django.test.TestCase as all tests are wrapped in
a transaction that never gets committed.
"""
immediate_using = DEFAULT_DB_ALIAS if using is None else using
def on_commit(func, using=None):
using = DEFAULT_DB_ALIAS if using is None else using
if using == immediate_using:
func()
with mock.patch('django.db.transaction.on_commit',
side_effect=on_commit) as patch:
yield patch
}}}
This also allows us to assert against the `on_commit` mock's
`assert_called_*` methods.
Right now the proper way to test for `on_commit` execution is to use a
`TransactionTestCase` which doesn't performs this transaction wrapping.
I guess the documentation of `TestCase`, `TransactionTestCase` and
`on_commit` could be enhanced in this regard and a solution similar to
`immediate_on_commit` could be added to `TestCase`.
Thoughts?
--
Ticket URL: <https://code.djangoproject.com/ticket/30457#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/064.6d0d6629be302a06d77c5ab6e2758c11%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.