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