Browse Source

Fixed #25388 -- Added an option to allow disabling of migrations during test database creation.

Jon Dufresne 5 years ago
parent
commit
f5ebdfce5c

+ 11 - 10
django/db/backends/base/creation.py

@@ -61,16 +61,17 @@ class BaseDatabaseCreation:
         settings.DATABASES[self.connection.alias]["NAME"] = test_database_name
         self.connection.settings_dict["NAME"] = test_database_name
 
-        # We report migrate messages at one level lower than that requested.
-        # This ensures we don't get flooded with messages during testing
-        # (unless you really ask to be flooded).
-        call_command(
-            'migrate',
-            verbosity=max(verbosity - 1, 0),
-            interactive=False,
-            database=self.connection.alias,
-            run_syncdb=True,
-        )
+        if self.connection.settings_dict['TEST']['MIGRATE']:
+            # We report migrate messages at one level lower than that
+            # requested. This ensures we don't get flooded with messages during
+            # testing (unless you really ask to be flooded).
+            call_command(
+                'migrate',
+                verbosity=max(verbosity - 1, 0),
+                interactive=False,
+                database=self.connection.alias,
+                run_syncdb=True,
+            )
 
         # We then serialize the current state of the database into a string
         # and store it on the connection. This slightly horrific process is so people

+ 9 - 2
django/db/utils.py

@@ -194,8 +194,15 @@ class ConnectionHandler:
             raise ConnectionDoesNotExist("The connection %s doesn't exist" % alias)
 
         test_settings = conn.setdefault('TEST', {})
-        for key in ['CHARSET', 'COLLATION', 'NAME', 'MIRROR']:
-            test_settings.setdefault(key, None)
+        default_test_settings = [
+            ('CHARSET', None),
+            ('COLLATION', None),
+            ('MIGRATE', True),
+            ('MIRROR', None),
+            ('NAME', None),
+        ]
+        for key, value in default_test_settings:
+            test_settings.setdefault(key, value)
 
     def __getitem__(self, alias):
         if hasattr(self._connections, alias):

+ 3 - 2
docs/ref/django-admin.txt

@@ -1371,8 +1371,9 @@ Preserves the test database between test runs. This has the advantage of
 skipping both the create and destroy actions which can greatly decrease the
 time to run tests, especially those in a large test suite. If the test database
 does not exist, it will be created on the first run and then preserved for each
-subsequent run. Any unapplied migrations will also be applied to the test
-database before running the test suite.
+subsequent run. Unless the :setting:`MIGRATE <TEST_MIGRATE>` test setting is
+``False``, any unapplied migrations will also be applied to the test database
+before running the test suite.
 
 .. django-admin-option:: --reverse, -r
 

+ 16 - 3
docs/ref/settings.txt

@@ -739,6 +739,17 @@ The creation-order dependencies of the database. See the documentation
 on :ref:`controlling the creation order of test databases
 <topics-testing-creation-dependencies>` for details.
 
+.. setting:: TEST_MIGRATE
+
+``MIGRATE``
+^^^^^^^^^^^
+
+.. versionadded:: 3.1
+
+Default: ``True``
+
+When set to ``False``, migrations won't run when creating the test database.
+
 .. setting:: TEST_MIRROR
 
 ``MIRROR``
@@ -2034,9 +2045,11 @@ automatically create the package if it doesn't already exist.
 When you supply ``None`` as a value for an app, Django will consider the app as
 an app without migrations regardless of an existing ``migrations`` submodule.
 This can be used, for example, in a test settings file to skip migrations while
-testing (tables will still be created for the apps' models). If this is used in
-your general project settings, remember to use the :option:`migrate
---run-syncdb` option if you want to create tables for the app.
+testing (tables will still be created for the apps' models). To disable
+migrations for all apps during tests, you can set the
+:setting:`MIGRATE <TEST_MIGRATE>` to ``True`` instead. If ``MIGRATION_MODULES``
+is used in your general project settings, remember to use the
+:option:`migrate --run-syncdb` option if you want to create tables for the app.
 
 .. setting:: MONTH_DAY_FORMAT
 

+ 3 - 0
docs/releases/3.1.txt

@@ -237,6 +237,9 @@ Tests
   allow running a test without collecting the result and catching exceptions.
   This can be used to support running tests under a debugger.
 
+* The new :setting:`MIGRATE <TEST_MIGRATE>` test database setting allows
+  disabling of migrations during a test database creation.
+
 URLs
 ~~~~
 

+ 28 - 1
tests/backends/base/test_creation.py

@@ -1,6 +1,7 @@
 import copy
+from unittest import mock
 
-from django.db import DEFAULT_DB_ALIAS, connections
+from django.db import DEFAULT_DB_ALIAS, connection, connections
 from django.db.backends.base.creation import (
     TEST_DATABASE_PREFIX, BaseDatabaseCreation,
 )
@@ -40,3 +41,29 @@ class TestDbSignatureTests(SimpleTestCase):
         test_connection.settings_dict['TEST'] = {'NAME': test_name}
         signature = BaseDatabaseCreation(test_connection).test_db_signature()
         self.assertEqual(signature[3], test_name)
+
+
+@mock.patch.object(connection, 'ensure_connection')
+@mock.patch('django.core.management.commands.migrate.Command.handle', return_value=None)
+class TestDbCreationTests(SimpleTestCase):
+    def test_migrate_test_setting_false(self, mocked_migrate, mocked_ensure_connection):
+        creation = connection.creation_class(connection)
+        saved_settings = copy.deepcopy(connection.settings_dict)
+        try:
+            connection.settings_dict['TEST']['MIGRATE'] = False
+            with mock.patch.object(creation, '_create_test_db'):
+                creation.create_test_db(verbosity=0, autoclobber=True, serialize=False)
+            mocked_migrate.assert_not_called()
+        finally:
+            connection.settings_dict = saved_settings
+
+    def test_migrate_test_setting_true(self, mocked_migrate, mocked_ensure_connection):
+        creation = connection.creation_class(connection)
+        saved_settings = copy.deepcopy(connection.settings_dict)
+        try:
+            connection.settings_dict['TEST']['MIGRATE'] = True
+            with mock.patch.object(creation, '_create_test_db'):
+                creation.create_test_db(verbosity=0, autoclobber=True, serialize=False)
+            mocked_migrate.assert_called_once()
+        finally:
+            connection.settings_dict = saved_settings