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

This commit is contained in:
Jon Dufresne 2019-11-12 19:49:09 -08:00 committed by Mariusz Felisiak
parent 3e5b349535
commit f5ebdfce5c
6 changed files with 70 additions and 18 deletions

View File

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

View File

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

View File

@ -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 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 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 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 subsequent run. Unless the :setting:`MIGRATE <TEST_MIGRATE>` test setting is
database before running the test suite. ``False``, any unapplied migrations will also be applied to the test database
before running the test suite.
.. django-admin-option:: --reverse, -r .. django-admin-option:: --reverse, -r

View File

@ -739,6 +739,17 @@ The creation-order dependencies of the database. See the documentation
on :ref:`controlling the creation order of test databases on :ref:`controlling the creation order of test databases
<topics-testing-creation-dependencies>` for details. <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 .. setting:: TEST_MIRROR
``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 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. 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 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 testing (tables will still be created for the apps' models). To disable
your general project settings, remember to use the :option:`migrate migrations for all apps during tests, you can set the
--run-syncdb` option if you want to create tables for the app. :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 .. setting:: MONTH_DAY_FORMAT

View File

@ -237,6 +237,9 @@ Tests
allow running a test without collecting the result and catching exceptions. allow running a test without collecting the result and catching exceptions.
This can be used to support running tests under a debugger. 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 URLs
~~~~ ~~~~

View File

@ -1,6 +1,7 @@
import copy 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 ( from django.db.backends.base.creation import (
TEST_DATABASE_PREFIX, BaseDatabaseCreation, TEST_DATABASE_PREFIX, BaseDatabaseCreation,
) )
@ -40,3 +41,29 @@ class TestDbSignatureTests(SimpleTestCase):
test_connection.settings_dict['TEST'] = {'NAME': test_name} test_connection.settings_dict['TEST'] = {'NAME': test_name}
signature = BaseDatabaseCreation(test_connection).test_db_signature() signature = BaseDatabaseCreation(test_connection).test_db_signature()
self.assertEqual(signature[3], test_name) 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