123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775 |
- """
- Tests for django test runner
- """
- import collections.abc
- import unittest
- from unittest import mock
- from admin_scripts.tests import AdminScriptTestCase
- from django import db
- from django.conf import settings
- from django.core.exceptions import ImproperlyConfigured
- from django.core.management import call_command
- from django.core.management.base import SystemCheckError
- from django.test import (
- SimpleTestCase, TransactionTestCase, skipUnlessDBFeature,
- )
- from django.test.runner import (
- DiscoverRunner, Shuffler, reorder_test_bin, reorder_tests, shuffle_tests,
- )
- from django.test.testcases import connections_support_transactions
- from django.test.utils import (
- captured_stderr, dependency_ordered, get_unique_databases_and_mirrors,
- iter_test_cases,
- )
- from django.utils.deprecation import RemovedInDjango50Warning
- from .models import B, Person, Through
- class MySuite:
- def __init__(self):
- self.tests = []
- def addTest(self, test):
- self.tests.append(test)
- def __iter__(self):
- yield from self.tests
- class TestSuiteTests(SimpleTestCase):
- def build_test_suite(self, test_classes, suite=None, suite_class=None):
- if suite_class is None:
- suite_class = unittest.TestSuite
- if suite is None:
- suite = suite_class()
- loader = unittest.defaultTestLoader
- for test_class in test_classes:
- tests = loader.loadTestsFromTestCase(test_class)
- subsuite = suite_class()
- # Only use addTest() to simplify testing a custom TestSuite.
- for test in tests:
- subsuite.addTest(test)
- suite.addTest(subsuite)
- return suite
- def make_test_suite(self, suite=None, suite_class=None):
- class Tests1(unittest.TestCase):
- def test1(self):
- pass
- def test2(self):
- pass
- class Tests2(unittest.TestCase):
- def test1(self):
- pass
- def test2(self):
- pass
- return self.build_test_suite(
- (Tests1, Tests2),
- suite=suite,
- suite_class=suite_class,
- )
- def assertTestNames(self, tests, expected):
- # Each test.id() has a form like the following:
- # "test_runner.tests.IterTestCasesTests.test_iter_test_cases.<locals>.Tests1.test1".
- # It suffices to check only the last two parts.
- names = ['.'.join(test.id().split('.')[-2:]) for test in tests]
- self.assertEqual(names, expected)
- def test_iter_test_cases_basic(self):
- suite = self.make_test_suite()
- tests = iter_test_cases(suite)
- self.assertTestNames(tests, expected=[
- 'Tests1.test1', 'Tests1.test2', 'Tests2.test1', 'Tests2.test2',
- ])
- def test_iter_test_cases_string_input(self):
- msg = (
- "Test 'a' must be a test case or test suite not string (was found "
- "in 'abc')."
- )
- with self.assertRaisesMessage(TypeError, msg):
- list(iter_test_cases('abc'))
- def test_iter_test_cases_iterable_of_tests(self):
- class Tests(unittest.TestCase):
- def test1(self):
- pass
- def test2(self):
- pass
- tests = list(unittest.defaultTestLoader.loadTestsFromTestCase(Tests))
- actual_tests = iter_test_cases(tests)
- self.assertTestNames(actual_tests, expected=[
- 'Tests.test1', 'Tests.test2',
- ])
- def test_iter_test_cases_custom_test_suite_class(self):
- suite = self.make_test_suite(suite_class=MySuite)
- tests = iter_test_cases(suite)
- self.assertTestNames(tests, expected=[
- 'Tests1.test1', 'Tests1.test2', 'Tests2.test1', 'Tests2.test2',
- ])
- def test_iter_test_cases_mixed_test_suite_classes(self):
- suite = self.make_test_suite(suite=MySuite())
- child_suite = list(suite)[0]
- self.assertNotIsInstance(child_suite, MySuite)
- tests = list(iter_test_cases(suite))
- self.assertEqual(len(tests), 4)
- self.assertNotIsInstance(tests[0], unittest.TestSuite)
- def make_tests(self):
- """Return an iterable of tests."""
- suite = self.make_test_suite()
- tests = list(iter_test_cases(suite))
- return tests
- def test_shuffle_tests(self):
- tests = self.make_tests()
- # Choose a seed that shuffles both the classes and methods.
- shuffler = Shuffler(seed=9)
- shuffled_tests = shuffle_tests(tests, shuffler)
- self.assertIsInstance(shuffled_tests, collections.abc.Iterator)
- self.assertTestNames(shuffled_tests, expected=[
- 'Tests2.test1', 'Tests2.test2', 'Tests1.test2', 'Tests1.test1',
- ])
- def test_reorder_test_bin_no_arguments(self):
- tests = self.make_tests()
- reordered_tests = reorder_test_bin(tests)
- self.assertIsInstance(reordered_tests, collections.abc.Iterator)
- self.assertTestNames(reordered_tests, expected=[
- 'Tests1.test1', 'Tests1.test2', 'Tests2.test1', 'Tests2.test2',
- ])
- def test_reorder_test_bin_reverse(self):
- tests = self.make_tests()
- reordered_tests = reorder_test_bin(tests, reverse=True)
- self.assertIsInstance(reordered_tests, collections.abc.Iterator)
- self.assertTestNames(reordered_tests, expected=[
- 'Tests2.test2', 'Tests2.test1', 'Tests1.test2', 'Tests1.test1',
- ])
- def test_reorder_test_bin_random(self):
- tests = self.make_tests()
- # Choose a seed that shuffles both the classes and methods.
- shuffler = Shuffler(seed=9)
- reordered_tests = reorder_test_bin(tests, shuffler=shuffler)
- self.assertIsInstance(reordered_tests, collections.abc.Iterator)
- self.assertTestNames(reordered_tests, expected=[
- 'Tests2.test1', 'Tests2.test2', 'Tests1.test2', 'Tests1.test1',
- ])
- def test_reorder_test_bin_random_and_reverse(self):
- tests = self.make_tests()
- # Choose a seed that shuffles both the classes and methods.
- shuffler = Shuffler(seed=9)
- reordered_tests = reorder_test_bin(tests, shuffler=shuffler, reverse=True)
- self.assertIsInstance(reordered_tests, collections.abc.Iterator)
- self.assertTestNames(reordered_tests, expected=[
- 'Tests1.test1', 'Tests1.test2', 'Tests2.test2', 'Tests2.test1',
- ])
- def test_reorder_tests_same_type_consecutive(self):
- """Tests of the same type are made consecutive."""
- tests = self.make_tests()
- # Move the last item to the front.
- tests.insert(0, tests.pop())
- self.assertTestNames(tests, expected=[
- 'Tests2.test2', 'Tests1.test1', 'Tests1.test2', 'Tests2.test1',
- ])
- reordered_tests = reorder_tests(tests, classes=[])
- self.assertTestNames(reordered_tests, expected=[
- 'Tests2.test2', 'Tests2.test1', 'Tests1.test1', 'Tests1.test2',
- ])
- def test_reorder_tests_random(self):
- tests = self.make_tests()
- # Choose a seed that shuffles both the classes and methods.
- shuffler = Shuffler(seed=9)
- reordered_tests = reorder_tests(tests, classes=[], shuffler=shuffler)
- self.assertIsInstance(reordered_tests, collections.abc.Iterator)
- self.assertTestNames(reordered_tests, expected=[
- 'Tests2.test1', 'Tests2.test2', 'Tests1.test2', 'Tests1.test1',
- ])
- def test_reorder_tests_random_mixed_classes(self):
- tests = self.make_tests()
- # Move the last item to the front.
- tests.insert(0, tests.pop())
- shuffler = Shuffler(seed=9)
- self.assertTestNames(tests, expected=[
- 'Tests2.test2', 'Tests1.test1', 'Tests1.test2', 'Tests2.test1',
- ])
- reordered_tests = reorder_tests(tests, classes=[], shuffler=shuffler)
- self.assertTestNames(reordered_tests, expected=[
- 'Tests2.test1', 'Tests2.test2', 'Tests1.test2', 'Tests1.test1',
- ])
- def test_reorder_tests_reverse_with_duplicates(self):
- class Tests1(unittest.TestCase):
- def test1(self):
- pass
- class Tests2(unittest.TestCase):
- def test2(self):
- pass
- def test3(self):
- pass
- suite = self.build_test_suite((Tests1, Tests2))
- subsuite = list(suite)[0]
- suite.addTest(subsuite)
- tests = list(iter_test_cases(suite))
- self.assertTestNames(tests, expected=[
- 'Tests1.test1', 'Tests2.test2', 'Tests2.test3', 'Tests1.test1',
- ])
- reordered_tests = reorder_tests(tests, classes=[])
- self.assertTestNames(reordered_tests, expected=[
- 'Tests1.test1', 'Tests2.test2', 'Tests2.test3',
- ])
- reordered_tests = reorder_tests(tests, classes=[], reverse=True)
- self.assertTestNames(reordered_tests, expected=[
- 'Tests2.test3', 'Tests2.test2', 'Tests1.test1',
- ])
- class DependencyOrderingTests(unittest.TestCase):
- def test_simple_dependencies(self):
- raw = [
- ('s1', ('s1_db', ['alpha'])),
- ('s2', ('s2_db', ['bravo'])),
- ('s3', ('s3_db', ['charlie'])),
- ]
- dependencies = {
- 'alpha': ['charlie'],
- 'bravo': ['charlie'],
- }
- ordered = dependency_ordered(raw, dependencies=dependencies)
- ordered_sigs = [sig for sig, value in ordered]
- self.assertIn('s1', ordered_sigs)
- self.assertIn('s2', ordered_sigs)
- self.assertIn('s3', ordered_sigs)
- self.assertLess(ordered_sigs.index('s3'), ordered_sigs.index('s1'))
- self.assertLess(ordered_sigs.index('s3'), ordered_sigs.index('s2'))
- def test_chained_dependencies(self):
- raw = [
- ('s1', ('s1_db', ['alpha'])),
- ('s2', ('s2_db', ['bravo'])),
- ('s3', ('s3_db', ['charlie'])),
- ]
- dependencies = {
- 'alpha': ['bravo'],
- 'bravo': ['charlie'],
- }
- ordered = dependency_ordered(raw, dependencies=dependencies)
- ordered_sigs = [sig for sig, value in ordered]
- self.assertIn('s1', ordered_sigs)
- self.assertIn('s2', ordered_sigs)
- self.assertIn('s3', ordered_sigs)
- # Explicit dependencies
- self.assertLess(ordered_sigs.index('s2'), ordered_sigs.index('s1'))
- self.assertLess(ordered_sigs.index('s3'), ordered_sigs.index('s2'))
- # Implied dependencies
- self.assertLess(ordered_sigs.index('s3'), ordered_sigs.index('s1'))
- def test_multiple_dependencies(self):
- raw = [
- ('s1', ('s1_db', ['alpha'])),
- ('s2', ('s2_db', ['bravo'])),
- ('s3', ('s3_db', ['charlie'])),
- ('s4', ('s4_db', ['delta'])),
- ]
- dependencies = {
- 'alpha': ['bravo', 'delta'],
- 'bravo': ['charlie'],
- 'delta': ['charlie'],
- }
- ordered = dependency_ordered(raw, dependencies=dependencies)
- ordered_sigs = [sig for sig, aliases in ordered]
- self.assertIn('s1', ordered_sigs)
- self.assertIn('s2', ordered_sigs)
- self.assertIn('s3', ordered_sigs)
- self.assertIn('s4', ordered_sigs)
- # Explicit dependencies
- self.assertLess(ordered_sigs.index('s2'), ordered_sigs.index('s1'))
- self.assertLess(ordered_sigs.index('s4'), ordered_sigs.index('s1'))
- self.assertLess(ordered_sigs.index('s3'), ordered_sigs.index('s2'))
- self.assertLess(ordered_sigs.index('s3'), ordered_sigs.index('s4'))
- # Implicit dependencies
- self.assertLess(ordered_sigs.index('s3'), ordered_sigs.index('s1'))
- def test_circular_dependencies(self):
- raw = [
- ('s1', ('s1_db', ['alpha'])),
- ('s2', ('s2_db', ['bravo'])),
- ]
- dependencies = {
- 'bravo': ['alpha'],
- 'alpha': ['bravo'],
- }
- with self.assertRaises(ImproperlyConfigured):
- dependency_ordered(raw, dependencies=dependencies)
- def test_own_alias_dependency(self):
- raw = [
- ('s1', ('s1_db', ['alpha', 'bravo']))
- ]
- dependencies = {
- 'alpha': ['bravo']
- }
- with self.assertRaises(ImproperlyConfigured):
- dependency_ordered(raw, dependencies=dependencies)
- # reordering aliases shouldn't matter
- raw = [
- ('s1', ('s1_db', ['bravo', 'alpha']))
- ]
- with self.assertRaises(ImproperlyConfigured):
- dependency_ordered(raw, dependencies=dependencies)
- class MockTestRunner:
- def __init__(self, *args, **kwargs):
- pass
- MockTestRunner.run_tests = mock.Mock(return_value=[])
- class ManageCommandTests(unittest.TestCase):
- def test_custom_test_runner(self):
- call_command('test', 'sites',
- testrunner='test_runner.tests.MockTestRunner')
- MockTestRunner.run_tests.assert_called_with(('sites',))
- def test_bad_test_runner(self):
- with self.assertRaises(AttributeError):
- call_command('test', 'sites', testrunner='test_runner.NonexistentRunner')
- def test_time_recorded(self):
- with captured_stderr() as stderr:
- call_command('test', '--timing', 'sites', testrunner='test_runner.tests.MockTestRunner')
- self.assertIn('Total run took', stderr.getvalue())
- class CustomTestRunnerOptionsSettingsTests(AdminScriptTestCase):
- """
- Custom runners can add command line arguments. The runner is specified
- through a settings file.
- """
- def setUp(self):
- super().setUp()
- settings = {
- 'TEST_RUNNER': '\'test_runner.runner.CustomOptionsTestRunner\'',
- }
- self.write_settings('settings.py', sdict=settings)
- def test_default_options(self):
- args = ['test', '--settings=test_project.settings']
- out, err = self.run_django_admin(args)
- self.assertNoOutput(err)
- self.assertOutput(out, '1:2:3')
- def test_default_and_given_options(self):
- args = ['test', '--settings=test_project.settings', '--option_b=foo']
- out, err = self.run_django_admin(args)
- self.assertNoOutput(err)
- self.assertOutput(out, '1:foo:3')
- def test_option_name_and_value_separated(self):
- args = ['test', '--settings=test_project.settings', '--option_b', 'foo']
- out, err = self.run_django_admin(args)
- self.assertNoOutput(err)
- self.assertOutput(out, '1:foo:3')
- def test_all_options_given(self):
- args = ['test', '--settings=test_project.settings', '--option_a=bar',
- '--option_b=foo', '--option_c=31337']
- out, err = self.run_django_admin(args)
- self.assertNoOutput(err)
- self.assertOutput(out, 'bar:foo:31337')
- class CustomTestRunnerOptionsCmdlineTests(AdminScriptTestCase):
- """
- Custom runners can add command line arguments when the runner is specified
- using --testrunner.
- """
- def setUp(self):
- super().setUp()
- self.write_settings('settings.py')
- def test_testrunner_option(self):
- args = [
- 'test', '--testrunner', 'test_runner.runner.CustomOptionsTestRunner',
- '--option_a=bar', '--option_b=foo', '--option_c=31337'
- ]
- out, err = self.run_django_admin(args, 'test_project.settings')
- self.assertNoOutput(err)
- self.assertOutput(out, 'bar:foo:31337')
- def test_testrunner_equals(self):
- args = [
- 'test', '--testrunner=test_runner.runner.CustomOptionsTestRunner',
- '--option_a=bar', '--option_b=foo', '--option_c=31337'
- ]
- out, err = self.run_django_admin(args, 'test_project.settings')
- self.assertNoOutput(err)
- self.assertOutput(out, 'bar:foo:31337')
- def test_no_testrunner(self):
- args = ['test', '--testrunner']
- out, err = self.run_django_admin(args, 'test_project.settings')
- self.assertIn('usage', err)
- self.assertNotIn('Traceback', err)
- self.assertNoOutput(out)
- class Ticket17477RegressionTests(AdminScriptTestCase):
- def setUp(self):
- super().setUp()
- self.write_settings('settings.py')
- def test_ticket_17477(self):
- """'manage.py help test' works after r16352."""
- args = ['help', 'test']
- out, err = self.run_manage(args)
- self.assertNoOutput(err)
- class SQLiteInMemoryTestDbs(TransactionTestCase):
- available_apps = ['test_runner']
- databases = {'default', 'other'}
- @unittest.skipUnless(all(db.connections[conn].vendor == 'sqlite' for conn in db.connections),
- "This is an sqlite-specific issue")
- def test_transaction_support(self):
- # Assert connections mocking is appropriately applied by preventing
- # any attempts at calling create_test_db on the global connection
- # objects.
- for connection in db.connections.all():
- create_test_db = mock.patch.object(
- connection.creation,
- 'create_test_db',
- side_effect=AssertionError("Global connection object shouldn't be manipulated.")
- )
- create_test_db.start()
- self.addCleanup(create_test_db.stop)
- for option_key, option_value in (
- ('NAME', ':memory:'), ('TEST', {'NAME': ':memory:'})):
- tested_connections = db.ConnectionHandler({
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- option_key: option_value,
- },
- 'other': {
- 'ENGINE': 'django.db.backends.sqlite3',
- option_key: option_value,
- },
- })
- with mock.patch('django.test.utils.connections', new=tested_connections):
- other = tested_connections['other']
- DiscoverRunner(verbosity=0).setup_databases()
- msg = (
- "DATABASES setting '%s' option set to sqlite3's ':memory:' value "
- "shouldn't interfere with transaction support detection." % option_key
- )
- # Transaction support is properly initialized for the 'other' DB.
- self.assertTrue(other.features.supports_transactions, msg)
- # And all the DBs report that they support transactions.
- self.assertTrue(connections_support_transactions(), msg)
- class DummyBackendTest(unittest.TestCase):
- def test_setup_databases(self):
- """
- setup_databases() doesn't fail with dummy database backend.
- """
- tested_connections = db.ConnectionHandler({})
- with mock.patch('django.test.utils.connections', new=tested_connections):
- runner_instance = DiscoverRunner(verbosity=0)
- old_config = runner_instance.setup_databases()
- runner_instance.teardown_databases(old_config)
- class AliasedDefaultTestSetupTest(unittest.TestCase):
- def test_setup_aliased_default_database(self):
- """
- setup_databases() doesn't fail when 'default' is aliased
- """
- tested_connections = db.ConnectionHandler({
- 'default': {
- 'NAME': 'dummy'
- },
- 'aliased': {
- 'NAME': 'dummy'
- }
- })
- with mock.patch('django.test.utils.connections', new=tested_connections):
- runner_instance = DiscoverRunner(verbosity=0)
- old_config = runner_instance.setup_databases()
- runner_instance.teardown_databases(old_config)
- class SetupDatabasesTests(SimpleTestCase):
- def setUp(self):
- self.runner_instance = DiscoverRunner(verbosity=0)
- def test_setup_aliased_databases(self):
- tested_connections = db.ConnectionHandler({
- 'default': {
- 'ENGINE': 'django.db.backends.dummy',
- 'NAME': 'dbname',
- },
- 'other': {
- 'ENGINE': 'django.db.backends.dummy',
- 'NAME': 'dbname',
- }
- })
- with mock.patch('django.db.backends.dummy.base.DatabaseWrapper.creation_class') as mocked_db_creation:
- with mock.patch('django.test.utils.connections', new=tested_connections):
- old_config = self.runner_instance.setup_databases()
- self.runner_instance.teardown_databases(old_config)
- mocked_db_creation.return_value.destroy_test_db.assert_called_once_with('dbname', 0, False)
- def test_setup_test_database_aliases(self):
- """
- The default database must be the first because data migrations
- use the default alias by default.
- """
- tested_connections = db.ConnectionHandler({
- 'other': {
- 'ENGINE': 'django.db.backends.dummy',
- 'NAME': 'dbname',
- },
- 'default': {
- 'ENGINE': 'django.db.backends.dummy',
- 'NAME': 'dbname',
- }
- })
- with mock.patch('django.test.utils.connections', new=tested_connections):
- test_databases, _ = get_unique_databases_and_mirrors()
- self.assertEqual(
- test_databases,
- {
- ('', '', 'django.db.backends.dummy', 'test_dbname'): (
- 'dbname',
- ['default', 'other'],
- ),
- },
- )
- def test_destroy_test_db_restores_db_name(self):
- tested_connections = db.ConnectionHandler({
- 'default': {
- 'ENGINE': settings.DATABASES[db.DEFAULT_DB_ALIAS]["ENGINE"],
- 'NAME': 'xxx_test_database',
- },
- })
- # Using the real current name as old_name to not mess with the test suite.
- old_name = settings.DATABASES[db.DEFAULT_DB_ALIAS]["NAME"]
- with mock.patch('django.db.connections', new=tested_connections):
- tested_connections['default'].creation.destroy_test_db(old_name, verbosity=0, keepdb=True)
- self.assertEqual(tested_connections['default'].settings_dict["NAME"], old_name)
- def test_serialization(self):
- tested_connections = db.ConnectionHandler({
- 'default': {
- 'ENGINE': 'django.db.backends.dummy',
- },
- })
- with mock.patch('django.db.backends.dummy.base.DatabaseWrapper.creation_class') as mocked_db_creation:
- with mock.patch('django.test.utils.connections', new=tested_connections):
- self.runner_instance.setup_databases()
- mocked_db_creation.return_value.create_test_db.assert_called_once_with(
- verbosity=0, autoclobber=False, serialize=True, keepdb=False
- )
- def test_serialized_off(self):
- tested_connections = db.ConnectionHandler({
- 'default': {
- 'ENGINE': 'django.db.backends.dummy',
- 'TEST': {'SERIALIZE': False},
- },
- })
- msg = (
- 'The SERIALIZE test database setting is deprecated as it can be '
- 'inferred from the TestCase/TransactionTestCase.databases that '
- 'enable the serialized_rollback feature.'
- )
- with mock.patch('django.db.backends.dummy.base.DatabaseWrapper.creation_class') as mocked_db_creation:
- with mock.patch('django.test.utils.connections', new=tested_connections):
- with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
- self.runner_instance.setup_databases()
- mocked_db_creation.return_value.create_test_db.assert_called_once_with(
- verbosity=0, autoclobber=False, serialize=False, keepdb=False
- )
- @skipUnlessDBFeature('supports_sequence_reset')
- class AutoIncrementResetTest(TransactionTestCase):
- """
- Creating the same models in different test methods receive the same PK
- values since the sequences are reset before each test method.
- """
- available_apps = ['test_runner']
- reset_sequences = True
- def _test(self):
- # Regular model
- p = Person.objects.create(first_name='Jack', last_name='Smith')
- self.assertEqual(p.pk, 1)
- # Auto-created many-to-many through model
- p.friends.add(Person.objects.create(first_name='Jacky', last_name='Smith'))
- self.assertEqual(p.friends.through.objects.first().pk, 1)
- # Many-to-many through model
- b = B.objects.create()
- t = Through.objects.create(person=p, b=b)
- self.assertEqual(t.pk, 1)
- def test_autoincrement_reset1(self):
- self._test()
- def test_autoincrement_reset2(self):
- self._test()
- class EmptyDefaultDatabaseTest(unittest.TestCase):
- def test_empty_default_database(self):
- """
- An empty default database in settings does not raise an ImproperlyConfigured
- error when running a unit test that does not use a database.
- """
- tested_connections = db.ConnectionHandler({'default': {}})
- with mock.patch('django.db.connections', new=tested_connections):
- connection = tested_connections[db.utils.DEFAULT_DB_ALIAS]
- self.assertEqual(connection.settings_dict['ENGINE'], 'django.db.backends.dummy')
- connections_support_transactions()
- class RunTestsExceptionHandlingTests(unittest.TestCase):
- def test_run_checks_raises(self):
- """
- Teardown functions are run when run_checks() raises SystemCheckError.
- """
- with mock.patch('django.test.runner.DiscoverRunner.setup_test_environment'), \
- mock.patch('django.test.runner.DiscoverRunner.setup_databases'), \
- mock.patch('django.test.runner.DiscoverRunner.build_suite'), \
- mock.patch('django.test.runner.DiscoverRunner.run_checks', side_effect=SystemCheckError), \
- mock.patch('django.test.runner.DiscoverRunner.teardown_databases') as teardown_databases, \
- mock.patch('django.test.runner.DiscoverRunner.teardown_test_environment') as teardown_test_environment:
- runner = DiscoverRunner(verbosity=0, interactive=False)
- with self.assertRaises(SystemCheckError):
- runner.run_tests(['test_runner_apps.sample.tests_sample.TestDjangoTestCase'])
- self.assertTrue(teardown_databases.called)
- self.assertTrue(teardown_test_environment.called)
- def test_run_checks_raises_and_teardown_raises(self):
- """
- SystemCheckError is surfaced when run_checks() raises SystemCheckError
- and teardown databases() raises ValueError.
- """
- with mock.patch('django.test.runner.DiscoverRunner.setup_test_environment'), \
- mock.patch('django.test.runner.DiscoverRunner.setup_databases'), \
- mock.patch('django.test.runner.DiscoverRunner.build_suite'), \
- mock.patch('django.test.runner.DiscoverRunner.run_checks', side_effect=SystemCheckError), \
- mock.patch('django.test.runner.DiscoverRunner.teardown_databases', side_effect=ValueError) \
- as teardown_databases, \
- mock.patch('django.test.runner.DiscoverRunner.teardown_test_environment') as teardown_test_environment:
- runner = DiscoverRunner(verbosity=0, interactive=False)
- with self.assertRaises(SystemCheckError):
- runner.run_tests(['test_runner_apps.sample.tests_sample.TestDjangoTestCase'])
- self.assertTrue(teardown_databases.called)
- self.assertFalse(teardown_test_environment.called)
- def test_run_checks_passes_and_teardown_raises(self):
- """
- Exceptions on teardown are surfaced if no exceptions happen during
- run_checks().
- """
- with mock.patch('django.test.runner.DiscoverRunner.setup_test_environment'), \
- mock.patch('django.test.runner.DiscoverRunner.setup_databases'), \
- mock.patch('django.test.runner.DiscoverRunner.build_suite'), \
- mock.patch('django.test.runner.DiscoverRunner.run_checks'), \
- mock.patch('django.test.runner.DiscoverRunner.teardown_databases', side_effect=ValueError) \
- as teardown_databases, \
- mock.patch('django.test.runner.DiscoverRunner.teardown_test_environment') as teardown_test_environment:
- runner = DiscoverRunner(verbosity=0, interactive=False)
- with self.assertRaises(ValueError):
- # Suppress the output when running TestDjangoTestCase.
- with mock.patch('sys.stderr'):
- runner.run_tests(['test_runner_apps.sample.tests_sample.TestDjangoTestCase'])
- self.assertTrue(teardown_databases.called)
- self.assertFalse(teardown_test_environment.called)
- # RemovedInDjango50Warning
- class NoOpTestRunner(DiscoverRunner):
- def setup_test_environment(self, **kwargs):
- return
- def setup_databases(self, **kwargs):
- return
- def run_checks(self, databases):
- return
- def teardown_databases(self, old_config, **kwargs):
- return
- def teardown_test_environment(self, **kwargs):
- return
- class DiscoverRunnerExtraTestsDeprecationTests(SimpleTestCase):
- msg = 'The extra_tests argument is deprecated.'
- def get_runner(self):
- return NoOpTestRunner(verbosity=0, interactive=False)
- def test_extra_tests_build_suite(self):
- runner = self.get_runner()
- with self.assertWarnsMessage(RemovedInDjango50Warning, self.msg):
- runner.build_suite(extra_tests=[])
- def test_extra_tests_run_tests(self):
- runner = self.get_runner()
- with captured_stderr():
- with self.assertWarnsMessage(RemovedInDjango50Warning, self.msg):
- runner.run_tests(
- test_labels=['test_runner_apps.sample.tests_sample.EmptyTestCase'],
- extra_tests=[],
- )
|