Fixed #33264 -- Made test runner return non-zero error code for unexpected successes.

This commit is contained in:
Baptiste Mispelon 2021-11-04 15:31:26 +01:00 committed by Mariusz Felisiak
parent 1a5023883b
commit 91acfc3514
6 changed files with 51 additions and 2 deletions

View File

@ -875,7 +875,7 @@ class DiscoverRunner:
teardown_test_environment() teardown_test_environment()
def suite_result(self, suite, result, **kwargs): def suite_result(self, suite, result, **kwargs):
return len(result.failures) + len(result.errors) return len(result.failures) + len(result.errors) + len(result.unexpectedSuccesses)
def _get_databases(self, suite): def _get_databases(self, suite):
databases = {} databases = {}

View File

@ -260,6 +260,9 @@ Miscellaneous
:class:`~django.contrib.contenttypes.fields.GenericRelation` are now cached :class:`~django.contrib.contenttypes.fields.GenericRelation` are now cached
on the :class:`~django.db.models.Model` instance to which they belong. on the :class:`~django.db.models.Model` instance to which they belong.
* The Django test runner now returns a non-zero error code for unexpected
successes from tests marked with :py:func:`unittest.expectedFailure`.
.. _deprecated-features-4.1: .. _deprecated-features-4.1:
Features deprecated in 4.1 Features deprecated in 4.1

View File

@ -331,10 +331,15 @@ but it's pretty intuitive. You can consult the documentation of Python's
:mod:`unittest` library for details. :mod:`unittest` library for details.
Note that the return code for the test-runner script is 1 for any number of Note that the return code for the test-runner script is 1 for any number of
failed and erroneous tests. If all the tests pass, the return code is 0. This failed tests (whether the failure was caused by an error, a failed assertion,
or an unexpected success). If all the tests pass, the return code is 0. This
feature is useful if you're using the test-runner script in a shell script and feature is useful if you're using the test-runner script in a shell script and
need to test for success or failure at that level. need to test for success or failure at that level.
.. versionchanged:: 4.1
In older versions, the return code was 0 for unexpected successes.
.. _speeding-up-tests-auth-hashers: .. _speeding-up-tests-auth-hashers:
Speeding up the tests Speeding up the tests

View File

@ -644,6 +644,24 @@ class DiscoverRunnerTests(SimpleTestCase):
runner.log('log message', level) runner.log('log message', level)
self.assertEqual(cm.output, [expected]) self.assertEqual(cm.output, [expected])
def test_suite_result_with_failure(self):
cases = [
(1, 'FailureTestCase'),
(1, 'ErrorTestCase'),
(0, 'ExpectedFailureTestCase'),
(1, 'UnexpectedSuccessTestCase'),
]
runner = DiscoverRunner(verbosity=0)
for expected_failures, testcase in cases:
with self.subTest(testcase=testcase):
suite = runner.build_suite([
f'test_runner_apps.failures.tests_failures.{testcase}',
])
with captured_stderr():
result = runner.run_suite(suite)
failures = runner.suite_result(suite, result)
self.assertEqual(failures, expected_failures)
class DiscoverRunnerGetDatabasesTests(SimpleTestCase): class DiscoverRunnerGetDatabasesTests(SimpleTestCase):
runner = DiscoverRunner(verbosity=2) runner = DiscoverRunner(verbosity=2)

View File

@ -0,0 +1,23 @@
from unittest import TestCase, expectedFailure
class FailureTestCase(TestCase):
def test_sample(self):
self.assertEqual(0, 1)
class ErrorTestCase(TestCase):
def test_sample(self):
raise Exception('test')
class ExpectedFailureTestCase(TestCase):
@expectedFailure
def test_sample(self):
self.assertEqual(0, 1)
class UnexpectedSuccessTestCase(TestCase):
@expectedFailure
def test_sample(self):
self.assertEqual(1, 1)