Refs #20392 -- Load fixtures once within TestCase

This commit is contained in:
Thomas Chaumeny 2014-12-04 14:05:59 +01:00 committed by Tim Graham
parent 0dea81cd6d
commit 119154ca7f
2 changed files with 50 additions and 33 deletions

View File

@ -915,24 +915,46 @@ class TestCase(TransactionTestCase):
On database backends with no transaction support, TestCase behaves as On database backends with no transaction support, TestCase behaves as
TransactionTestCase. TransactionTestCase.
""" """
@classmethod
def _enter_atomics(cls):
"""Helper method to open atomic blocks for multiple databases"""
atomics = {}
for db_name in cls._databases_names():
atomics[db_name] = transaction.atomic(using=db_name)
atomics[db_name].__enter__()
return atomics
@classmethod
def _rollback_atomics(cls, atomics):
"""Rollback atomic blocks opened through the previous method"""
for db_name in reversed(cls._databases_names()):
transaction.set_rollback(True, using=db_name)
atomics[db_name].__exit__(None, None, None)
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(TestCase, cls).setUpClass() super(TestCase, cls).setUpClass()
if not connections_support_transactions(): if not connections_support_transactions():
return return
cls.cls_atomics = {} cls.cls_atomics = cls._enter_atomics()
for db_name in cls._databases_names():
cls.cls_atomics[db_name] = transaction.atomic(using=db_name) if cls.fixtures:
cls.cls_atomics[db_name].__enter__() for db_name in cls._databases_names(include_mirrors=False):
try:
call_command('loaddata', *cls.fixtures, **{
'verbosity': 0,
'commit': False,
'database': db_name,
})
except Exception:
cls._rollback_atomics(cls.cls_atomics)
raise
cls.setUpTestData() cls.setUpTestData()
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
if connections_support_transactions(): if connections_support_transactions():
for db_name in reversed(cls._databases_names()): cls._rollback_atomics(cls.cls_atomics)
transaction.set_rollback(True, using=db_name)
cls.cls_atomics[db_name].__exit__(None, None, None)
for conn in connections.all(): for conn in connections.all():
conn.close() conn.close()
super(TestCase, cls).tearDownClass() super(TestCase, cls).tearDownClass()
@ -955,32 +977,12 @@ class TestCase(TransactionTestCase):
return super(TestCase, self)._fixture_setup() return super(TestCase, self)._fixture_setup()
assert not self.reset_sequences, 'reset_sequences cannot be used on TestCase instances' assert not self.reset_sequences, 'reset_sequences cannot be used on TestCase instances'
self.atomics = self._enter_atomics()
self.atomics = {}
for db_name in self._databases_names():
self.atomics[db_name] = transaction.atomic(using=db_name)
self.atomics[db_name].__enter__()
for db_name in self._databases_names(include_mirrors=False):
if self.fixtures:
try:
call_command('loaddata', *self.fixtures,
**{
'verbosity': 0,
'commit': False,
'database': db_name,
})
except Exception:
self._fixture_teardown()
raise
def _fixture_teardown(self): def _fixture_teardown(self):
if not connections_support_transactions(): if not connections_support_transactions():
return super(TestCase, self)._fixture_teardown() return super(TestCase, self)._fixture_teardown()
self._rollback_atomics(self.atomics)
for db_name in reversed(self._databases_names()):
transaction.set_rollback(True, using=db_name)
self.atomics[db_name].__exit__(None, None, None)
class CheckCondition(object): class CheckCondition(object):

View File

@ -67,6 +67,25 @@ to accept expressions other than aggregates. Aggregates are now able to
reference multiple fields, as well as perform arithmetic, similar to ``F()`` reference multiple fields, as well as perform arithmetic, similar to ``F()``
objects. objects.
``TestCase`` data setup
~~~~~~~~~~~~~~~~~~~~~~~
:class:`~django.test.TestCase` has been refactored to allow for data
initialization at the class level using transactions and savepoints. Database
backends which do not support transactions, like MySQL with the MyISAM storage
engine, will still be able to run these tests but won't benefit from the
improvements. Tests are now run within two nested
:func:`~django.db.transaction.atomic()` blocks: one for the whole class and one
for each test.
* The class method
:meth:`TestCase.setUpTestData() <django.test.TestCase.setUpTestData>` adds
the ability to setup test data at the class level. Using this technique can
speed up the tests as compared to using ``setUp()``.
* Fixture loading within ``TestCase`` is now performed once for the whole
``TestCase``.
Minor features Minor features
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
@ -515,10 +534,6 @@ Tests
* The :func:`~django.test.override_settings` decorator can now affect the * The :func:`~django.test.override_settings` decorator can now affect the
master router in :setting:`DATABASE_ROUTERS`. master router in :setting:`DATABASE_ROUTERS`.
* Added the ability to setup test data at the class level using
:meth:`TestCase.setUpTestData() <django.test.TestCase.setUpTestData>`. Using
this technique can speed up the tests as compared to using ``setUp()``.
* Added test client support for file uploads with file-like objects. * Added test client support for file uploads with file-like objects.
Validators Validators