Loading django/test/testcases.py +59 −15 Original line number Diff line number Diff line Loading @@ -786,10 +786,11 @@ class TransactionTestCase(SimpleTestCase): raise def _databases_names(self, include_mirrors=True): @classmethod def _databases_names(cls, include_mirrors=True): # If the test case has a multi_db=True flag, act on all databases, # including mirrors or not. Otherwise, just on the default DB. if getattr(self, 'multi_db', False): if getattr(cls, 'multi_db', False): return [alias for alias in connections if include_mirrors or not connections[alias].settings_dict['TEST']['MIRROR']] else: Loading Loading @@ -829,6 +830,9 @@ class TransactionTestCase(SimpleTestCase): call_command('loaddata', *self.fixtures, **{'verbosity': 0, 'database': db_name}) def _should_reload_connections(self): return True def _post_teardown(self): """Performs any post-test things. This includes: Loading @@ -839,12 +843,13 @@ class TransactionTestCase(SimpleTestCase): try: self._fixture_teardown() super(TransactionTestCase, self)._post_teardown() if self._should_reload_connections(): # Some DB cursors include SQL statements as part of cursor # creation. If you have a test that does rollback, the effect of # these statements is lost, which can effect the operation of # creation. If you have a test that does a rollback, the effect # of these statements is lost, which can affect the operation of # tests (e.g., losing a timezone setting causing objects to be # created with the wrong time). To make sure this doesn't happen, # get a clean connection at the start of every test. # created with the wrong time). To make sure this doesn't # happen, get a clean connection at the start of every test. for conn in connections.all(): conn.close() finally: Loading Loading @@ -899,15 +904,54 @@ def connections_support_transactions(): class TestCase(TransactionTestCase): """ Does basically the same as TransactionTestCase, but surrounds every test with a transaction, monkey-patches the real transaction management routines to do nothing, and rollsback the test transaction at the end of the test. You have to use TransactionTestCase, if you need transaction management inside a test. Similar to TransactionTestCase, but uses `transaction.atomic()` to achieve test isolation. In most situation, TestCase should be prefered to TransactionTestCase as it allows faster execution. However, there are some situations where using TransactionTestCase might be necessary (e.g. testing some transactional behavior). On database backends with no transaction support, TestCase behaves as TransactionTestCase. """ @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.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) for conn in connections.all(): conn.close() super(TestCase, cls).tearDownClass() @classmethod def setUpTestData(cls): """Load initial data for the TestCase""" pass def _should_reload_connections(self): if connections_support_transactions(): return False return super(TestCase, self)._should_reload_connections() def _fixture_setup(self): if not connections_support_transactions(): # If the backend does not support transactions, we should reload # class data before each test self.setUpTestData() return super(TestCase, self)._fixture_setup() assert not self.reset_sequences, 'reset_sequences cannot be used on TestCase instances' Loading docs/releases/1.8.txt +12 −0 Original line number Diff line number Diff line Loading @@ -507,6 +507,10 @@ 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()``. Validators ^^^^^^^^^^ Loading Loading @@ -743,6 +747,14 @@ The new package is available `on Github`_ and on PyPI. .. _on GitHub: https://github.com/django/django-formtools/ Database connection reloading between tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Django previously closed database connections between each test within a ``TestCase``. This is no longer the case as Django now wraps the whole ``TestCase`` within a transaction. If some of your tests relied on the old behavior, you should have them inherit from ``TransactionTestCase`` instead. Miscellaneous ~~~~~~~~~~~~~ Loading docs/topics/testing/tools.txt +33 −1 Original line number Diff line number Diff line Loading @@ -691,13 +691,45 @@ additions, including: * Automatic loading of fixtures. * Wraps each test in a transaction. * Wraps the tests within two nested ``atomic`` blocks: one for the whole class and one for each test. * Creates a TestClient instance. * Django-specific assertions for testing for things like redirection and form errors. .. classmethod:: TestCase.setUpTestData() .. versionadded:: 1.8 The class-level ``atomic`` block described above allows the creation of initial data at the class level, once for the whole ``TestCase``. This technique allows for faster tests as compared to using ``setUp()``. For example:: from django.test import TestCase class MyTests(TestCase): @classmethod def setUpTestData(cls): # Set up data for the whole TestCase cls.foo = Foo.objects.create(bar="Test") ... def test1(self): # Some test using self.foo ... def test2(self): # Some other test using self.foo ... Note that if the tests are run on a database with no transaction support (for instance, MySQL with the MyISAM engine), ``setUpTestData()`` will be called before each test, negating the speed benefits. .. warning:: If you want to test some specific database transaction behavior, you should Loading tests/backends/tests.py +11 −8 Original line number Diff line number Diff line Loading @@ -345,13 +345,14 @@ class ParameterHandlingTest(TestCase): # Unfortunately, the following tests would be a good test to run on all # backends, but it breaks MySQL hard. Until #13711 is fixed, it can't be run # everywhere (although it would be an effective test of #13711). class LongNameTest(TestCase): class LongNameTest(TransactionTestCase): """Long primary keys and model names can result in a sequence name that exceeds the database limits, which will result in truncation on certain databases (e.g., Postgres). The backend needs to use the correct sequence name in last_insert_id and other places, so check it is. Refs #8901. """ available_apps = ['backends'] def test_sequence_name_length_limits_create(self): """Test creation of model with long name and long pk name doesn't error. Ref #8901""" Loading Loading @@ -465,7 +466,9 @@ class EscapingChecksDebug(EscapingChecks): pass class BackendTestCase(TestCase): class BackendTestCase(TransactionTestCase): available_apps = ['backends'] def create_squares_with_executemany(self, args): self.create_squares(args, 'format', True) Loading Loading @@ -653,9 +656,8 @@ class BackendTestCase(TestCase): """ Test the documented API of connection.queries. """ reset_queries() with connection.cursor() as cursor: reset_queries() cursor.execute("SELECT 1" + connection.features.bare_select_suffix) self.assertEqual(1, len(connection.queries)) Loading Loading @@ -823,7 +825,9 @@ class FkConstraintsTests(TransactionTestCase): transaction.set_rollback(True) class ThreadTests(TestCase): class ThreadTests(TransactionTestCase): available_apps = ['backends'] def test_default_connection_thread_local(self): """ Loading Loading @@ -987,9 +991,7 @@ class MySQLPKZeroTests(TestCase): models.Square.objects.create(id=0, root=0, square=1) class DBConstraintTestCase(TransactionTestCase): available_apps = ['backends'] class DBConstraintTestCase(TestCase): def test_can_reference_existent(self): obj = models.Object.objects.create() Loading Loading @@ -1066,6 +1068,7 @@ class DBTestSettingsRenamedTests(IgnoreAllDeprecationWarningsMixin, TestCase): @classmethod def setUpClass(cls): super(DBTestSettingsRenamedTests, cls).setUpClass() # Silence "UserWarning: Overriding setting DATABASES can lead to # unexpected behavior." cls.warning_classes.append(UserWarning) Loading tests/fixtures_migration/tests.py +2 −2 Original line number Diff line number Diff line from django.test import TestCase from django.test import TransactionTestCase from django.core import management from .models import Book class TestNoInitialDataLoading(TestCase): class TestNoInitialDataLoading(TransactionTestCase): """ Apps with migrations should ignore initial data. This test can be removed in Django 1.9 when migrations become required and initial data is no longer Loading Loading
django/test/testcases.py +59 −15 Original line number Diff line number Diff line Loading @@ -786,10 +786,11 @@ class TransactionTestCase(SimpleTestCase): raise def _databases_names(self, include_mirrors=True): @classmethod def _databases_names(cls, include_mirrors=True): # If the test case has a multi_db=True flag, act on all databases, # including mirrors or not. Otherwise, just on the default DB. if getattr(self, 'multi_db', False): if getattr(cls, 'multi_db', False): return [alias for alias in connections if include_mirrors or not connections[alias].settings_dict['TEST']['MIRROR']] else: Loading Loading @@ -829,6 +830,9 @@ class TransactionTestCase(SimpleTestCase): call_command('loaddata', *self.fixtures, **{'verbosity': 0, 'database': db_name}) def _should_reload_connections(self): return True def _post_teardown(self): """Performs any post-test things. This includes: Loading @@ -839,12 +843,13 @@ class TransactionTestCase(SimpleTestCase): try: self._fixture_teardown() super(TransactionTestCase, self)._post_teardown() if self._should_reload_connections(): # Some DB cursors include SQL statements as part of cursor # creation. If you have a test that does rollback, the effect of # these statements is lost, which can effect the operation of # creation. If you have a test that does a rollback, the effect # of these statements is lost, which can affect the operation of # tests (e.g., losing a timezone setting causing objects to be # created with the wrong time). To make sure this doesn't happen, # get a clean connection at the start of every test. # created with the wrong time). To make sure this doesn't # happen, get a clean connection at the start of every test. for conn in connections.all(): conn.close() finally: Loading Loading @@ -899,15 +904,54 @@ def connections_support_transactions(): class TestCase(TransactionTestCase): """ Does basically the same as TransactionTestCase, but surrounds every test with a transaction, monkey-patches the real transaction management routines to do nothing, and rollsback the test transaction at the end of the test. You have to use TransactionTestCase, if you need transaction management inside a test. Similar to TransactionTestCase, but uses `transaction.atomic()` to achieve test isolation. In most situation, TestCase should be prefered to TransactionTestCase as it allows faster execution. However, there are some situations where using TransactionTestCase might be necessary (e.g. testing some transactional behavior). On database backends with no transaction support, TestCase behaves as TransactionTestCase. """ @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.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) for conn in connections.all(): conn.close() super(TestCase, cls).tearDownClass() @classmethod def setUpTestData(cls): """Load initial data for the TestCase""" pass def _should_reload_connections(self): if connections_support_transactions(): return False return super(TestCase, self)._should_reload_connections() def _fixture_setup(self): if not connections_support_transactions(): # If the backend does not support transactions, we should reload # class data before each test self.setUpTestData() return super(TestCase, self)._fixture_setup() assert not self.reset_sequences, 'reset_sequences cannot be used on TestCase instances' Loading
docs/releases/1.8.txt +12 −0 Original line number Diff line number Diff line Loading @@ -507,6 +507,10 @@ 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()``. Validators ^^^^^^^^^^ Loading Loading @@ -743,6 +747,14 @@ The new package is available `on Github`_ and on PyPI. .. _on GitHub: https://github.com/django/django-formtools/ Database connection reloading between tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Django previously closed database connections between each test within a ``TestCase``. This is no longer the case as Django now wraps the whole ``TestCase`` within a transaction. If some of your tests relied on the old behavior, you should have them inherit from ``TransactionTestCase`` instead. Miscellaneous ~~~~~~~~~~~~~ Loading
docs/topics/testing/tools.txt +33 −1 Original line number Diff line number Diff line Loading @@ -691,13 +691,45 @@ additions, including: * Automatic loading of fixtures. * Wraps each test in a transaction. * Wraps the tests within two nested ``atomic`` blocks: one for the whole class and one for each test. * Creates a TestClient instance. * Django-specific assertions for testing for things like redirection and form errors. .. classmethod:: TestCase.setUpTestData() .. versionadded:: 1.8 The class-level ``atomic`` block described above allows the creation of initial data at the class level, once for the whole ``TestCase``. This technique allows for faster tests as compared to using ``setUp()``. For example:: from django.test import TestCase class MyTests(TestCase): @classmethod def setUpTestData(cls): # Set up data for the whole TestCase cls.foo = Foo.objects.create(bar="Test") ... def test1(self): # Some test using self.foo ... def test2(self): # Some other test using self.foo ... Note that if the tests are run on a database with no transaction support (for instance, MySQL with the MyISAM engine), ``setUpTestData()`` will be called before each test, negating the speed benefits. .. warning:: If you want to test some specific database transaction behavior, you should Loading
tests/backends/tests.py +11 −8 Original line number Diff line number Diff line Loading @@ -345,13 +345,14 @@ class ParameterHandlingTest(TestCase): # Unfortunately, the following tests would be a good test to run on all # backends, but it breaks MySQL hard. Until #13711 is fixed, it can't be run # everywhere (although it would be an effective test of #13711). class LongNameTest(TestCase): class LongNameTest(TransactionTestCase): """Long primary keys and model names can result in a sequence name that exceeds the database limits, which will result in truncation on certain databases (e.g., Postgres). The backend needs to use the correct sequence name in last_insert_id and other places, so check it is. Refs #8901. """ available_apps = ['backends'] def test_sequence_name_length_limits_create(self): """Test creation of model with long name and long pk name doesn't error. Ref #8901""" Loading Loading @@ -465,7 +466,9 @@ class EscapingChecksDebug(EscapingChecks): pass class BackendTestCase(TestCase): class BackendTestCase(TransactionTestCase): available_apps = ['backends'] def create_squares_with_executemany(self, args): self.create_squares(args, 'format', True) Loading Loading @@ -653,9 +656,8 @@ class BackendTestCase(TestCase): """ Test the documented API of connection.queries. """ reset_queries() with connection.cursor() as cursor: reset_queries() cursor.execute("SELECT 1" + connection.features.bare_select_suffix) self.assertEqual(1, len(connection.queries)) Loading Loading @@ -823,7 +825,9 @@ class FkConstraintsTests(TransactionTestCase): transaction.set_rollback(True) class ThreadTests(TestCase): class ThreadTests(TransactionTestCase): available_apps = ['backends'] def test_default_connection_thread_local(self): """ Loading Loading @@ -987,9 +991,7 @@ class MySQLPKZeroTests(TestCase): models.Square.objects.create(id=0, root=0, square=1) class DBConstraintTestCase(TransactionTestCase): available_apps = ['backends'] class DBConstraintTestCase(TestCase): def test_can_reference_existent(self): obj = models.Object.objects.create() Loading Loading @@ -1066,6 +1068,7 @@ class DBTestSettingsRenamedTests(IgnoreAllDeprecationWarningsMixin, TestCase): @classmethod def setUpClass(cls): super(DBTestSettingsRenamedTests, cls).setUpClass() # Silence "UserWarning: Overriding setting DATABASES can lead to # unexpected behavior." cls.warning_classes.append(UserWarning) Loading
tests/fixtures_migration/tests.py +2 −2 Original line number Diff line number Diff line from django.test import TestCase from django.test import TransactionTestCase from django.core import management from .models import Book class TestNoInitialDataLoading(TestCase): class TestNoInitialDataLoading(TransactionTestCase): """ Apps with migrations should ignore initial data. This test can be removed in Django 1.9 when migrations become required and initial data is no longer Loading