Skip to content

Commit c552fed

Browse files
committed
Fix interaction between db and transaction_db fixtures
This adds a new helper method (`_django_db_fixture_helper`), which is being called from `db` and `transaction_db`. The intermediate helper function (in contrast to using an internal fixture) is necessary for setting up the `django_db` mark. Fixes #126
1 parent 8c39344 commit c552fed

File tree

3 files changed

+70
-35
lines changed

3 files changed

+70
-35
lines changed

docs/changelog.rst

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

4+
NEXT
5+
----
6+
7+
* Fix interaction between ``db`` and ``transaction_db`` fixtures (#126).
8+
49
2.6.2
510
-----
611

pytest_django/fixtures.py

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,39 @@ def teardown_database():
5959
if not request.config.getvalue('reuse_db'):
6060
request.addfinalizer(teardown_database)
6161

62+
def _django_db_fixture_helper(transactional, request, _django_cursor_wrapper):
63+
if is_django_unittest(request.node):
64+
return
65+
66+
if transactional:
67+
_django_cursor_wrapper.enable()
68+
69+
def flushdb():
70+
"""Flush the database and close database connections"""
71+
# Django does this by default *before* each test
72+
# instead of after.
73+
from django.db import connections
74+
from django.core.management import call_command
75+
76+
for db in connections:
77+
call_command('flush', verbosity=0,
78+
interactive=False, database=db)
79+
for conn in connections.all():
80+
conn.close()
81+
82+
request.addfinalizer(_django_cursor_wrapper.disable)
83+
request.addfinalizer(flushdb)
84+
else:
85+
if 'live_server' in request.funcargnames:
86+
return
87+
from django.test import TestCase
88+
89+
_django_cursor_wrapper.enable()
90+
_django_cursor_wrapper._is_transactional = False
91+
case = TestCase(methodName='__init__')
92+
case._pre_setup()
93+
request.addfinalizer(_django_cursor_wrapper.disable)
94+
request.addfinalizer(case._post_teardown)
6295

6396
################ User visible fixtures ################
6497

@@ -70,24 +103,16 @@ def db(request, _django_db_setup, _django_cursor_wrapper):
70103
This database will be setup with the default fixtures and will
71104
have the transaction management disabled. At the end of the test
72105
the transaction will be rolled back to undo any changes to the
73-
database. This is more limited then the ``transaction_db``
106+
database. This is more limited then the ``transactional_db``
74107
resource but faster.
75108
76-
If both this and ``transaction_db`` are requested then the
77-
database setup will behave as only ``transaction_db`` was
109+
If both this and ``transactional_db`` are requested then the
110+
database setup will behave as only ``transactional_db`` was
78111
requested.
79112
"""
80-
if ('transactional_db' not in request.funcargnames and
81-
'live_server' not in request.funcargnames and
82-
not is_django_unittest(request.node)):
83-
84-
from django.test import TestCase
85-
86-
_django_cursor_wrapper.enable()
87-
case = TestCase(methodName='__init__')
88-
case._pre_setup()
89-
request.addfinalizer(_django_cursor_wrapper.disable)
90-
request.addfinalizer(case._post_teardown)
113+
if 'transactional_db' in request.funcargnames:
114+
return request.getfuncargvalue('transactional_db')
115+
return _django_db_fixture_helper(False, request, _django_cursor_wrapper)
91116

92117

93118
@pytest.fixture(scope='function')
@@ -99,27 +124,10 @@ def transactional_db(request, _django_db_setup, _django_cursor_wrapper):
99124
100125
If you want to use the database with transactions you must request
101126
this resource. If both this and ``db`` are requested then the
102-
database setup will behave as only ``transaction_db`` was
127+
database setup will behave as only ``transactional_db`` was
103128
requested.
104129
"""
105-
if not is_django_unittest(request.node):
106-
_django_cursor_wrapper.enable()
107-
108-
def flushdb():
109-
"""Flush the database and close database connections"""
110-
# Django does this by default *before* each test
111-
# instead of after.
112-
from django.db import connections
113-
from django.core.management import call_command
114-
115-
for db in connections:
116-
call_command('flush', verbosity=0,
117-
interactive=False, database=db)
118-
for conn in connections.all():
119-
conn.close()
120-
121-
request.addfinalizer(_django_cursor_wrapper.disable)
122-
request.addfinalizer(flushdb)
130+
return _django_db_fixture_helper(True, request, _django_cursor_wrapper)
123131

124132

125133
@pytest.fixture()

tests/test_database.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99

1010

1111
def noop_transactions():
12-
"""Test whether transactions are disabled
12+
"""Test whether transactions are disabled.
1313
1414
Return True if transactions are disabled, False if they are
1515
enabled.
1616
"""
1717

18-
# Newer versions of Django simply runs standard tests in an atomic block.
18+
# Newer versions of Django simply run standard tests in an atomic block.
1919
if hasattr(connection, 'in_atomic_block'):
2020
return connection.in_atomic_block
2121
else:
@@ -109,6 +109,28 @@ def test_fin(self, fin):
109109
pass
110110

111111

112+
class TestDatabaseFixturesBothOrder:
113+
@pytest.fixture
114+
def fixture_with_db(self, db):
115+
Item.objects.create(name='spam')
116+
117+
@pytest.fixture
118+
def fixture_with_transdb(self, transactional_db):
119+
Item.objects.create(name='spam')
120+
121+
def test_trans(self, fixture_with_transdb):
122+
pass
123+
124+
def test_db(self, fixture_with_db):
125+
pass
126+
127+
def test_db_trans(self, fixture_with_db, fixture_with_transdb):
128+
pass
129+
130+
def test_trans_db(self, fixture_with_transdb, fixture_with_db):
131+
pass
132+
133+
112134
class TestDatabaseMarker:
113135

114136
@pytest.mark.django_db

0 commit comments

Comments
 (0)