mirror of
https://github.com/django/django.git
synced 2024-12-22 09:05:43 +00:00
Fixed #35660 -- Made serialized_rollback and fixture data available in TransactionTestCase.setUpClass().
This commit is contained in:
parent
8eca3e9bce
commit
a060a22ee2
@ -208,6 +208,7 @@ class SimpleTestCase(unittest.TestCase):
|
||||
async_client_class = AsyncClient
|
||||
_overridden_settings = None
|
||||
_modified_settings = None
|
||||
_pre_setup_ran_eagerly = False
|
||||
|
||||
databases = set()
|
||||
_disallowed_database_msg = (
|
||||
@ -360,6 +361,9 @@ class SimpleTestCase(unittest.TestCase):
|
||||
|
||||
if not skipped:
|
||||
try:
|
||||
if self.__class__._pre_setup_ran_eagerly:
|
||||
self.__class__._pre_setup_ran_eagerly = False
|
||||
else:
|
||||
self._pre_setup()
|
||||
except Exception:
|
||||
if debug:
|
||||
@ -1090,6 +1094,7 @@ class TransactionTestCase(SimpleTestCase):
|
||||
|
||||
# Subclasses can enable only a subset of apps for faster tests
|
||||
available_apps = None
|
||||
_available_apps_calls_balanced = 0
|
||||
|
||||
# Subclasses can define fixtures which will be automatically installed.
|
||||
fixtures = None
|
||||
@ -1107,6 +1112,20 @@ class TransactionTestCase(SimpleTestCase):
|
||||
# This can be slow; this flag allows enabling on a per-case basis.
|
||||
serialized_rollback = False
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
if not issubclass(cls, TestCase):
|
||||
cls._pre_setup()
|
||||
cls._pre_setup_ran_eagerly = True
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super().tearDownClass()
|
||||
if not issubclass(cls, TestCase) and cls._available_apps_calls_balanced > 0:
|
||||
apps.unset_available_apps()
|
||||
cls._available_apps_calls_balanced -= 1
|
||||
|
||||
@classmethod
|
||||
def _pre_setup(cls):
|
||||
"""
|
||||
@ -1119,6 +1138,7 @@ class TransactionTestCase(SimpleTestCase):
|
||||
super()._pre_setup()
|
||||
if cls.available_apps is not None:
|
||||
apps.set_available_apps(cls.available_apps)
|
||||
cls._available_apps_calls_balanced += 1
|
||||
setting_changed.send(
|
||||
sender=settings._wrapped.__class__,
|
||||
setting="INSTALLED_APPS",
|
||||
@ -1216,8 +1236,9 @@ class TransactionTestCase(SimpleTestCase):
|
||||
for conn in connections.all(initialized_only=True):
|
||||
conn.close()
|
||||
finally:
|
||||
if self.available_apps is not None:
|
||||
if self.__class__.available_apps is not None:
|
||||
apps.unset_available_apps()
|
||||
self.__class__._available_apps_calls_balanced -= 1
|
||||
setting_changed.send(
|
||||
sender=settings._wrapped.__class__,
|
||||
setting="INSTALLED_APPS",
|
||||
|
@ -260,6 +260,11 @@ Tests
|
||||
failures easier to read and enables :option:`test --pdb` to directly enter
|
||||
into the failing test method.
|
||||
|
||||
* Data loaded from :attr:`~django.test.TransactionTestCase.fixtures` and from
|
||||
migrations enabled with :ref:`serialized_rollback=True
|
||||
<test-case-serialized-rollback>` are now available during
|
||||
``TransactionTestCase.setUpClass()``.
|
||||
|
||||
URLs
|
||||
~~~~
|
||||
|
||||
|
@ -280,6 +280,11 @@ To prevent serialized data from being loaded twice, setting
|
||||
:data:`~django.db.models.signals.post_migrate` signal when flushing the test
|
||||
database.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
For :class:`TransactionTestCase`, serialized migration data is made
|
||||
available during ``setUpClass()``.
|
||||
|
||||
Other test conditions
|
||||
---------------------
|
||||
|
||||
|
@ -1262,25 +1262,35 @@ subclass::
|
||||
|
||||
Here's specifically what will happen:
|
||||
|
||||
* At the start of each test, before ``setUp()`` is run, Django will flush the
|
||||
database, returning the database to the state it was in directly after
|
||||
:djadmin:`migrate` was called.
|
||||
* During ``setUpClass()``, all the named fixtures are installed. In this
|
||||
example, Django will install any JSON fixture named ``mammals``, followed by
|
||||
any fixture named ``birds``. See the :ref:`fixtures-explanation` topic for
|
||||
more details on defining and installing fixtures.
|
||||
|
||||
* Then, all the named fixtures are installed. In this example, Django will
|
||||
install any JSON fixture named ``mammals``, followed by any fixture named
|
||||
``birds``. See the :ref:`fixtures-explanation` topic for more details on
|
||||
defining and installing fixtures.
|
||||
For most unit tests using :class:`TestCase`, Django doesn't need to do
|
||||
anything else, because transactions are used to clean the database after each
|
||||
test for performance reasons. But for :class:`TransactionTestCase`, the
|
||||
following actions will take place:
|
||||
|
||||
For performance reasons, :class:`TestCase` loads fixtures once for the entire
|
||||
test class, before :meth:`~TestCase.setUpTestData`, instead of before each
|
||||
test, and it uses transactions to clean the database before each test. In any case,
|
||||
you can be certain that the outcome of a test will not be affected by another
|
||||
test or by the order of test execution.
|
||||
* At the end of each test Django will flush the database, returning the
|
||||
database to the state it was in directly after :djadmin:`migrate` was
|
||||
called.
|
||||
|
||||
* For each subsequent test, the fixtures will be reloaded before ``setUp()``
|
||||
is run.
|
||||
|
||||
In any case, you can be certain that the outcome of a test will not be
|
||||
affected by another test or by the order of test execution.
|
||||
|
||||
By default, fixtures are only loaded into the ``default`` database. If you are
|
||||
using multiple databases and set :attr:`TransactionTestCase.databases`,
|
||||
fixtures will be loaded into all specified databases.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
For :class:`TransactionTestCase`, fixtures were made available during
|
||||
``setUpClass()``.
|
||||
|
||||
URLconf configuration
|
||||
---------------------
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
from django.core.management import call_command
|
||||
from django.test import TestCase, TransactionTestCase
|
||||
|
||||
from .models import Book
|
||||
@ -19,6 +20,26 @@ class MigrationDataPersistenceTestCase(TransactionTestCase):
|
||||
)
|
||||
|
||||
|
||||
class MigrationDataPersistenceClassSetup(TransactionTestCase):
|
||||
"""
|
||||
Data loaded in migrations is available during class setup if
|
||||
TransactionTestCase.serialized_rollback = True.
|
||||
"""
|
||||
|
||||
available_apps = ["migration_test_data_persistence"]
|
||||
serialized_rollback = True
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Simulate another TransactionTestCase having just torn down.
|
||||
call_command("flush", verbosity=0, interactive=False)
|
||||
super().setUpClass()
|
||||
cls.book = Book.objects.first()
|
||||
|
||||
def test_data_available_in_class_setup(self):
|
||||
self.assertIsInstance(self.book, Book)
|
||||
|
||||
|
||||
class MigrationDataNormalPersistenceTestCase(TestCase):
|
||||
"""
|
||||
Data loaded in migrations is available on TestCase
|
||||
|
@ -4,7 +4,7 @@ from django.db import connections
|
||||
from django.test import TestCase, TransactionTestCase, override_settings
|
||||
from django.test.testcases import DatabaseOperationForbidden
|
||||
|
||||
from .models import Car
|
||||
from .models import Car, Person
|
||||
|
||||
|
||||
class TestSerializedRollbackInhibitsPostMigrate(TransactionTestCase):
|
||||
@ -68,3 +68,16 @@ class DisallowedDatabaseQueriesTests(TransactionTestCase):
|
||||
)
|
||||
with self.assertRaisesMessage(DatabaseOperationForbidden, message):
|
||||
Car.objects.using("other").get()
|
||||
|
||||
|
||||
class FixtureAvailableInSetUpClassTest(TransactionTestCase):
|
||||
available_apps = ["test_utils"]
|
||||
fixtures = ["person.json"]
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.elvis = Person.objects.get(name="Elvis Presley")
|
||||
|
||||
def test_fixture_loaded_during_class_setup(self):
|
||||
self.assertIsInstance(self.elvis, Person)
|
||||
|
@ -1214,7 +1214,7 @@ class XMLEqualTests(SimpleTestCase):
|
||||
|
||||
|
||||
class SkippingExtraTests(TestCase):
|
||||
fixtures = ["should_not_be_loaded.json"]
|
||||
fixtures = ["person.json"]
|
||||
|
||||
# HACK: This depends on internals of our TestCase subclasses
|
||||
def __call__(self, result=None):
|
||||
|
Loading…
Reference in New Issue
Block a user