Skip to content

Commit ea704d9

Browse files
committed
Copied most of the PR pytest-dev#353 with a few adjustments, like getfixturevalue
1 parent 94cccb9 commit ea704d9

File tree

4 files changed

+63
-6
lines changed

4 files changed

+63
-6
lines changed

docs/changelog.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
Changelog
22
=========
33

4+
3.2.0
5+
-----
6+
7+
Features
8+
^^^^^^^^
9+
* Add support for serialized rollback in transactional tests.
10+
Thanks to Piotr Karkut for `the bug report
11+
<https://github.com/pytest-dev/pytest-django/issues/329>`_.
12+
413
3.1.2
514
-----
615

docs/helpers.rst

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ on what marks are and for notes on using_ them.
1313
.. _using: https://pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules
1414

1515

16-
``pytest.mark.django_db(transaction=False)`` - request database access
17-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16+
``pytest.mark.django_db(transaction=False, serialized_rollback=False)`` - request database access
17+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1818

1919
.. :py:function:: pytest.mark.django_db:
2020
@@ -38,6 +38,14 @@ when trying to access the database.
3838
uses. When ``transaction=True``, the behavior will be the same as
3939
`django.test.TransactionTestCase`_
4040

41+
:type serialized_rollback: bool
42+
:param serialized_rollback:
43+
The ``serialized_rollback`` argument enables `rollback emulation`_.
44+
After a `django.test.TransactionTestCase`_ runs, the database is
45+
flushed, destroying data created in data migrations. This is the
46+
default behavior of Django. Setting ``serialized_rollback=True``
47+
tells Django to restore that data.
48+
4149
.. note::
4250

4351
If you want access to the Django database *inside a fixture*
@@ -54,6 +62,7 @@ when trying to access the database.
5462
Test classes that subclass Python's ``unittest.TestCase`` need to have the
5563
marker applied in order to access the database.
5664

65+
.. _rollback emulation: https://docs.djangoproject.com/en/stable/topics/testing/overview/#rollback-emulation
5766
.. _django.test.TestCase: https://docs.djangoproject.com/en/dev/topics/testing/overview/#testcase
5867
.. _django.test.TransactionTestCase: https://docs.djangoproject.com/en/dev/topics/testing/overview/#transactiontestcase
5968

@@ -194,6 +203,16 @@ transaction support. This is only required for fixtures which need
194203
database access themselves. A test function would normally use the
195204
:py:func:`~pytest.mark.django_db` mark to signal it needs the database.
196205

206+
``serialized_rollback``
207+
~~~~~~~~~~~~~~~~~~~~~~~
208+
209+
When the ``transactional_db`` fixture is enabled, this fixture can be
210+
added to trigger `rollback emulation`_ and thus restores data created
211+
in data migrations after each transaction test. This is only required
212+
for fixtures which need to enforce this behavior. A test function
213+
would use :py:func:`~pytest.mark.django_db(serialized_rollback=True)`
214+
to request this behavior.
215+
197216
``live_server``
198217
~~~~~~~~~~~~~~~
199218

@@ -203,6 +222,12 @@ or by requesting it's string value: ``unicode(live_server)``. You can
203222
also directly concatenate a string to form a URL: ``live_server +
204223
'/foo``.
205224

225+
Since the live server and the tests run in different threads, they
226+
cannot share a database transaction. For this reason, ``live_server``
227+
depends on the ``transactional_db`` fixture. If tests depend on data
228+
created in data migrations, you should add the ``serialized_rollback``
229+
fixture.
230+
206231
``settings``
207232
~~~~~~~~~~~~
208233

pytest_django/fixtures.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ def teardown_database():
103103
request.addfinalizer(teardown_database)
104104

105105

106-
def _django_db_fixture_helper(transactional, request, django_db_blocker):
106+
def _django_db_fixture_helper(transactional, serialized_rollback,
107+
request, django_db_blocker):
107108
if is_django_unittest(request):
108109
return
109110

@@ -120,6 +121,7 @@ def _django_db_fixture_helper(transactional, request, django_db_blocker):
120121
from django.test import TestCase as django_case
121122

122123
test_case = django_case(methodName='__init__')
124+
test_case.serialized_rollback = serialized_rollback
123125
test_case._pre_setup()
124126
request.addfinalizer(test_case._post_teardown)
125127

@@ -152,7 +154,9 @@ def db(request, django_db_setup, django_db_blocker):
152154
or 'live_server' in request.funcargnames:
153155
getfixturevalue(request, 'transactional_db')
154156
else:
155-
_django_db_fixture_helper(False, request, django_db_blocker)
157+
_django_db_fixture_helper(
158+
transactional=False, serialized_rollback=False,
159+
request=request, django_db_blocker=django_db_blocker)
156160

157161

158162
@pytest.fixture(scope='function')
@@ -167,7 +171,23 @@ def transactional_db(request, django_db_setup, django_db_blocker):
167171
database setup will behave as only ``transactional_db`` was
168172
requested.
169173
"""
170-
_django_db_fixture_helper(True, request, django_db_blocker)
174+
serialized_rollback = False
175+
if 'serialized_rollback' in request.funcargnames:
176+
serialized_rollback = getfixturevalue(request, 'serialized_rollback')
177+
178+
_django_db_fixture_helper(
179+
transactional=True, serialized_rollback=serialized_rollback,
180+
request=request, django_db_blocker=django_db_blocker)
181+
182+
183+
@pytest.fixture(scope='function')
184+
def serialized_rollback(request):
185+
"""Enable serialized rollback after transaction test cases
186+
187+
This fixture only has an effect when the ``transactional_db``
188+
fixture is active, which happen as a side-effect of requesting
189+
``live_server``.
190+
"""
171191

172192

173193
@pytest.fixture()

pytest_django/plugin.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,8 @@ def _django_db_marker(request):
374374
getfixturevalue(request, 'transactional_db')
375375
else:
376376
getfixturevalue(request, 'db')
377+
if marker.serialized_rollback:
378+
request.getfixturevalue(request, 'serialized_rollback')
377379

378380

379381
@pytest.fixture(autouse=True, scope='class')
@@ -644,8 +646,9 @@ def validate_django_db(marker):
644646
It checks the signature and creates the `transaction` attribute on
645647
the marker which will have the correct value.
646648
"""
647-
def apifun(transaction=False):
649+
def apifun(transaction=False, serialized_rollback=False):
648650
marker.transaction = transaction
651+
marker.serialized_rollback = serialized_rollback
649652
apifun(*marker.args, **marker.kwargs)
650653

651654

0 commit comments

Comments
 (0)