Index: Doc/library/unittest.rst =================================================================== --- Doc/library/unittest.rst (revision 65022) +++ Doc/library/unittest.rst (working copy) @@ -485,7 +485,8 @@ applications which run test suites should provide alternate implementations. -.. function:: main([module[, defaultTest[, argv[, testRunner[, testLoader]]]]]) +.. function:: main([module[, defaultTest[, argv[, testRunner[, testLoader[, +exit]]]]]]) A command-line program that runs a set of tests; this is primarily for making test modules conveniently executable. The simplest use for this function is to @@ -497,6 +498,11 @@ The *testRunner* argument can either be a test runner class or an already created instance of it. + If *exit* is set to False (it is true by default) then running the tests will + not automaticallt exit at the end, which is useful if you are running with an + interactive interpreter and intend to continue using and should have no efect + when running from the command line. + In some cases, the existing tests may have been written using the :mod:`doctest` module. If so, that module provides a :class:`DocTestSuite` class that can automatically build :class:`unittest.TestSuite` instances from the existing Index: Lib/unittest.py =================================================================== --- Lib/unittest.py (revision 65022) +++ Lib/unittest.py (working copy) @@ -786,7 +786,7 @@ """ def __init__(self, module='__main__', defaultTest=None, argv=None, testRunner=TextTestRunner, - testLoader=defaultTestLoader): + testLoader=defaultTestLoader, exit=True): if type(module) == type(''): self.module = __import__(module) for part in module.split('.')[1:]: @@ -799,6 +799,7 @@ self.defaultTest = defaultTest self.testRunner = testRunner self.testLoader = testLoader + self.exit = exit self.progName = os.path.basename(argv[0]) self.parseArgs(argv) self.runTests() @@ -846,7 +847,8 @@ # it is assumed to be a TestRunner instance testRunner = self.testRunner result = testRunner.run(self.test) - sys.exit(not result.wasSuccessful()) + if self.exit: + sys.exit(not result.wasSuccessful()) main = TestProgram Index: Lib/test/test_unittest.py =================================================================== --- Lib/test/test_unittest.py (revision 65022) +++ Lib/test/test_unittest.py (working copy) @@ -10,6 +10,7 @@ import unittest from unittest import TestCase import types +import io ### Support code ################################################################ @@ -2284,6 +2285,40 @@ self.assertRaises(AssertionError, self.failIfAlmostEqual, 0, .1+.1j, places=0) +class Test_TestProgram(TestCase): + class FooBar(unittest.TestCase): + def testPass(self): + assert True + def testFail(self): + assert False + + class FooBarLoader(unittest.TestLoader): + """Test loader that returns a suite containing FooBar.""" + def loadTestsFromModule(self, module): + return self.suiteClass( + [self.loadTestsFromTestCase(Test_TestProgram.FooBar)]) + + def test_NonExit(self): + unittest.main(exit=False, + testRunner=unittest.TextTestRunner(stream=io.StringIO()), + testLoader=self.FooBarLoader()) + + def test_Exit(self): + self.failUnlessRaises( + SystemExit, + unittest.main, + testRunner=unittest.TextTestRunner(stream=io.StringIO()), + exit=True, + testLoader=self.FooBarLoader()) + + def test_ExitAsDefault(self): + self.failUnlessRaises( + SystemExit, + unittest.main, + testRunner=unittest.TextTestRunner(stream=io.StringIO()), + testLoader=self.FooBarLoader()) + + ###################################################################### ## Main ###################################################################### @@ -2291,7 +2326,7 @@ def test_main(): support.run_unittest(Test_TestCase, Test_TestLoader, Test_TestSuite, Test_TestResult, Test_FunctionTestCase, - Test_Assertions) + Test_Assertions, Test_TestProgram) if __name__ == "__main__": test_main()