Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
unittest runner: Exit code 5 if no tests were run
As discussed in https://discuss.python.org/t/unittest-fail-if-zero-tests-were-discovered/21498/7

It is common for test runner misconfiguration to fail to find any tests,
this should be an error.

Fixes: #62432
  • Loading branch information
stefanor committed Feb 19, 2023
commit 5e1a88de871f75701e1f2e93a001a6355b4d5b83
3 changes: 2 additions & 1 deletion Doc/library/unittest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2255,7 +2255,8 @@ Loading and running tests

The *testRunner* argument can either be a test runner class or an already
created instance of it. By default ``main`` calls :func:`sys.exit` with
an exit code indicating success or failure of the tests run.
an exit code indicating success (0) or failure (1) of the tests run.
An exit code of 5 indicates that no tests were run.

The *testLoader* argument has to be a :class:`TestLoader` instance,
and defaults to :data:`defaultTestLoader`.
Expand Down
17 changes: 16 additions & 1 deletion Lib/test/test_unittest/test_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ def testExpectedFailure(self):
def testUnexpectedSuccess(self):
pass

class Empty(unittest.TestCase):
pass

class TestLoader(unittest.TestLoader):
"""Test loader that returns a suite containing testsuite."""
Comment thread
stefanor marked this conversation as resolved.
Outdated

Expand Down Expand Up @@ -134,12 +137,13 @@ def test_NonExit(self):

def test_Exit(self):
stream = BufferedWriter()
with self.assertRaises(SystemExit):
with self.assertRaises(SystemExit) as cm:
unittest.main(
argv=["foobar"],
testRunner=unittest.TextTestRunner(stream=stream),
exit=True,
testLoader=self.TestLoader(self.FooBar))
self.assertEqual(cm.exception.code, 1)
out = stream.getvalue()
self.assertIn('\nFAIL: testFail ', out)
self.assertIn('\nERROR: testError ', out)
Expand All @@ -163,6 +167,17 @@ def test_ExitAsDefault(self):
'expected failures=1, unexpected successes=1)\n')
self.assertTrue(out.endswith(expected))

def test_ExitEmptySuite(self):
stream = BufferedWriter()
with self.assertRaises(SystemExit) as cm:
unittest.main(
argv=["empty"],
testRunner=unittest.TextTestRunner(stream=stream),
testLoader=self.TestLoader(self.Empty))
self.assertEqual(cm.exception.code, 5)
out = stream.getvalue()
self.assertIn('\nNO TESTS RUN\n', out)
Comment thread
stefanor marked this conversation as resolved.
Outdated


class InitialisableProgram(unittest.TestProgram):
exit = False
Expand Down
7 changes: 6 additions & 1 deletion Lib/unittest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,11 @@ def runTests(self):
testRunner = self.testRunner
self.result = testRunner.run(self.test)
if self.exit:
sys.exit(not self.result.wasSuccessful())
if self.result.testsRun == 0:
sys.exit(5)
elif not self.result.wasSuccessful():
sys.exit(1)
else:
sys.exit(0)
Comment thread
stefanor marked this conversation as resolved.
Outdated

main = TestProgram
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The :mod:`unittest` runner will now exit with status code 5, if no tests
Comment thread
stefanor marked this conversation as resolved.
Outdated
were run. It is common for test runner misconfiguration to fail to find any
tests, this should be an error.