summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJayden Kneller <jayden@arrai.com>2018-10-18 17:04:28 -0600
committerTim Graham <timograham@gmail.com>2018-10-30 12:01:48 -0400
commit916aecd29d5e3c5e02b620fbd38eac6d61ce6a5d (patch)
treeeac008f343aed8b6c56260b60c5c592461330da4
parent630f3d8b466570cb13c3f998007e1d9d7b9a5f9b (diff)
Fixed #29866 -- Made DiscoverRunner do tests tear down if running checks or tests raises an exception.
-rw-r--r--django/test/runner.py20
-rw-r--r--tests/test_runner/tests.py57
2 files changed, 73 insertions, 4 deletions
diff --git a/django/test/runner.py b/django/test/runner.py
index 38eb5c3be0..ed969cc42f 100644
--- a/django/test/runner.py
+++ b/django/test/runner.py
@@ -602,10 +602,22 @@ class DiscoverRunner:
self.setup_test_environment()
suite = self.build_suite(test_labels, extra_tests)
old_config = self.setup_databases()
- self.run_checks()
- result = self.run_suite(suite)
- self.teardown_databases(old_config)
- self.teardown_test_environment()
+ run_failed = False
+ try:
+ self.run_checks()
+ result = self.run_suite(suite)
+ except Exception:
+ run_failed = True
+ raise
+ finally:
+ try:
+ self.teardown_databases(old_config)
+ self.teardown_test_environment()
+ except Exception:
+ # Silence teardown exceptions if an exception was raised during
+ # runs to avoid shadowing it.
+ if not run_failed:
+ raise
return self.suite_result(suite, result)
diff --git a/tests/test_runner/tests.py b/tests/test_runner/tests.py
index 9717d329c1..b496d79369 100644
--- a/tests/test_runner/tests.py
+++ b/tests/test_runner/tests.py
@@ -10,6 +10,7 @@ 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 (
TestCase, TransactionTestCase, skipUnlessDBFeature, testcases,
)
@@ -407,3 +408,59 @@ class EmptyDefaultDatabaseTest(unittest.TestCase):
connection = testcases.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)