Commit 119154ca authored by Thomas Chaumeny's avatar Thomas Chaumeny Committed by Tim Graham
Browse files

Refs #20392 -- Load fixtures once within TestCase

parent 0dea81cd
Loading
Loading
Loading
Loading
+31 −29
Original line number Diff line number Diff line
@@ -915,24 +915,46 @@ class TestCase(TransactionTestCase):
    On database backends with no transaction support, TestCase behaves as
    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
    def setUpClass(cls):
        super(TestCase, cls).setUpClass()
        if not connections_support_transactions():
            return
        cls.cls_atomics = {}
        for db_name in cls._databases_names():
            cls.cls_atomics[db_name] = transaction.atomic(using=db_name)
            cls.cls_atomics[db_name].__enter__()
        cls.cls_atomics = cls._enter_atomics()

        if cls.fixtures:
            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()

    @classmethod
    def tearDownClass(cls):
        if connections_support_transactions():
            for db_name in reversed(cls._databases_names()):
                transaction.set_rollback(True, using=db_name)
                cls.cls_atomics[db_name].__exit__(None, None, None)
            cls._rollback_atomics(cls.cls_atomics)
            for conn in connections.all():
                conn.close()
        super(TestCase, cls).tearDownClass()
@@ -955,32 +977,12 @@ class TestCase(TransactionTestCase):
            return super(TestCase, self)._fixture_setup()

        assert not self.reset_sequences, 'reset_sequences cannot be used on TestCase instances'

        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
        self.atomics = self._enter_atomics()

    def _fixture_teardown(self):
        if not connections_support_transactions():
            return super(TestCase, self)._fixture_teardown()

        for db_name in reversed(self._databases_names()):
            transaction.set_rollback(True, using=db_name)
            self.atomics[db_name].__exit__(None, None, None)
        self._rollback_atomics(self.atomics)


class CheckCondition(object):
+19 −4
Original line number Diff line number Diff line
@@ -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()``
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
~~~~~~~~~~~~~~

@@ -515,10 +534,6 @@ Tests
* The :func:`~django.test.override_settings` decorator can now affect the
  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.

Validators