1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066 |
- """
- Tests for django test runner
- """
- import collections.abc
- import multiprocessing
- import os
- import sys
- 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,
- _init_worker,
- 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 .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()
- return list(iter_test_cases(suite))
- 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):
- if parallel := kwargs.get("parallel"):
- sys.stderr.write(f"parallel={parallel}")
- if durations := kwargs.get("durations"):
- sys.stderr.write(f"durations={durations}")
- 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())
- def test_durations(self):
- with captured_stderr() as stderr:
- call_command(
- "test",
- "--durations=10",
- "sites",
- testrunner="test_runner.tests.MockTestRunner",
- )
- self.assertIn("durations=10", stderr.getvalue())
- # Isolate from the real environment.
- @mock.patch.dict(os.environ, {}, clear=True)
- @mock.patch.object(multiprocessing, "cpu_count", return_value=12)
- class ManageCommandParallelTests(SimpleTestCase):
- @mock.patch.object(multiprocessing, "get_start_method", return_value="fork")
- def test_parallel_default(self, *mocked_objects):
- with captured_stderr() as stderr:
- call_command(
- "test",
- "--parallel",
- testrunner="test_runner.tests.MockTestRunner",
- )
- self.assertIn("parallel=12", stderr.getvalue())
- @mock.patch.object(multiprocessing, "get_start_method", return_value="fork")
- def test_parallel_auto(self, *mocked_objects):
- with captured_stderr() as stderr:
- call_command(
- "test",
- "--parallel=auto",
- testrunner="test_runner.tests.MockTestRunner",
- )
- self.assertIn("parallel=12", stderr.getvalue())
- def test_no_parallel(self, *mocked_objects):
- with captured_stderr() as stderr:
- call_command("test", testrunner="test_runner.tests.MockTestRunner")
- # Parallel is disabled by default.
- self.assertEqual(stderr.getvalue(), "")
- @mock.patch.object(multiprocessing, "get_start_method", return_value="spawn")
- def test_parallel_spawn(self, *mocked_objects):
- with captured_stderr() as stderr:
- call_command(
- "test",
- "--parallel=auto",
- testrunner="test_runner.tests.MockTestRunner",
- )
- self.assertIn("parallel=1", stderr.getvalue())
- @mock.patch.object(multiprocessing, "get_start_method", return_value="spawn")
- def test_no_parallel_spawn(self, *mocked_objects):
- with captured_stderr() as stderr:
- call_command(
- "test",
- testrunner="test_runner.tests.MockTestRunner",
- )
- self.assertEqual(stderr.getvalue(), "")
- @mock.patch.dict(os.environ, {"DJANGO_TEST_PROCESSES": "7"})
- @mock.patch.object(multiprocessing, "get_start_method", return_value="fork")
- def test_no_parallel_django_test_processes_env(self, *mocked_objects):
- with captured_stderr() as stderr:
- call_command("test", testrunner="test_runner.tests.MockTestRunner")
- self.assertEqual(stderr.getvalue(), "")
- @mock.patch.dict(os.environ, {"DJANGO_TEST_PROCESSES": "invalid"})
- @mock.patch.object(multiprocessing, "get_start_method", return_value="fork")
- def test_django_test_processes_env_non_int(self, *mocked_objects):
- with self.assertRaises(ValueError):
- call_command(
- "test",
- "--parallel",
- testrunner="test_runner.tests.MockTestRunner",
- )
- @mock.patch.dict(os.environ, {"DJANGO_TEST_PROCESSES": "7"})
- @mock.patch.object(multiprocessing, "get_start_method", return_value="fork")
- def test_django_test_processes_parallel_default(self, *mocked_objects):
- for parallel in ["--parallel", "--parallel=auto"]:
- with self.subTest(parallel=parallel):
- with captured_stderr() as stderr:
- call_command(
- "test",
- parallel,
- testrunner="test_runner.tests.MockTestRunner",
- )
- self.assertIn("parallel=7", 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 NoInitializeSuiteTestRunnerTests(SimpleTestCase):
- @mock.patch.object(multiprocessing, "get_start_method", return_value="spawn")
- @mock.patch(
- "django.test.runner.ParallelTestSuite.initialize_suite",
- side_effect=Exception("initialize_suite() is called."),
- )
- def test_no_initialize_suite_test_runner(self, *mocked_objects):
- """
- The test suite's initialize_suite() method must always be called when
- using spawn. It cannot rely on a test runner implementation.
- """
- class NoInitializeSuiteTestRunner(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
- def run_suite(self, suite, **kwargs):
- kwargs = self.get_test_runner_kwargs()
- runner = self.test_runner(**kwargs)
- return runner.run(suite)
- with self.assertRaisesMessage(Exception, "initialize_suite() is called."):
- runner = NoInitializeSuiteTestRunner(
- verbosity=0, interactive=False, parallel=2
- )
- runner.run_tests(
- [
- "test_runner_apps.sample.tests_sample.TestDjangoTestCase",
- "test_runner_apps.simple.tests",
- ]
- )
- class TestRunnerInitializerTests(SimpleTestCase):
- # Raise an exception to don't actually run tests.
- @mock.patch.object(
- multiprocessing, "Pool", side_effect=Exception("multiprocessing.Pool()")
- )
- def test_no_initialize_suite_test_runner(self, mocked_pool):
- class StubTestRunner(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
- def run_suite(self, suite, **kwargs):
- kwargs = self.get_test_runner_kwargs()
- runner = self.test_runner(**kwargs)
- return runner.run(suite)
- runner = StubTestRunner(
- verbosity=0, interactive=False, parallel=2, debug_mode=True
- )
- with self.assertRaisesMessage(Exception, "multiprocessing.Pool()"):
- runner.run_tests(
- [
- "test_runner_apps.sample.tests_sample.TestDjangoTestCase",
- "test_runner_apps.simple.tests",
- ]
- )
- # Initializer must be a function.
- self.assertIs(mocked_pool.call_args.kwargs["initializer"], _init_worker)
- initargs = mocked_pool.call_args.kwargs["initargs"]
- self.assertEqual(len(initargs), 7)
- self.assertEqual(initargs[5], True) # debug_mode
- self.assertEqual(initargs[6], {db.DEFAULT_DB_ALIAS}) # Used database aliases.
- 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"]
- try:
- new_test_connections = DiscoverRunner(verbosity=0).setup_databases()
- msg = (
- f"DATABASES setting '{option_key}' option set to sqlite3's "
- "':memory:' value shouldn't interfere with transaction support "
- "detection."
- )
- # 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)
- finally:
- for test_connection, _, _ in new_test_connections:
- test_connection._close()
- 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(unittest.TestCase):
- 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
- )
- @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)
|