diff options
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/unittest/case.py | 3 | ||||
-rw-r--r-- | Lib/unittest/suite.py | 28 | ||||
-rw-r--r-- | Lib/unittest/test/test_runner.py | 25 | ||||
-rw-r--r-- | Lib/unittest/test/test_setups.py | 62 |
4 files changed, 116 insertions, 2 deletions
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index d048303..91c4fbe 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -389,6 +389,9 @@ class TestCase(object): self.setUp() getattr(self, self._testMethodName)() self.tearDown() + while self._cleanups: + function, args, kwargs = self._cleanups.pop(-1) + function(*args, **kwargs) def skipTest(self, reason): """Skip this test.""" diff --git a/Lib/unittest/suite.py b/Lib/unittest/suite.py index 0072f20..a543e81 100644 --- a/Lib/unittest/suite.py +++ b/Lib/unittest/suite.py @@ -84,9 +84,16 @@ class TestSuite(BaseTestSuite): self._handleModuleTearDown(result) return result + def debug(self): + """Run the tests without collecting errors in a TestResult""" + debug = _DebugResult() + self._wrapped_run(debug, True) + self._tearDownPreviousClass(None, debug) + self._handleModuleTearDown(debug) + ################################ # private methods - def _wrapped_run(self, result): + def _wrapped_run(self, result, debug=False): for test in self: if result.shouldStop: break @@ -103,8 +110,10 @@ class TestSuite(BaseTestSuite): if hasattr(test, '_wrapped_run'): test._wrapped_run(result) - else: + elif not debug: test(result) + else: + test.debug() def _handleClassSetUp(self, test, result): previousClass = getattr(result, '_previousTestClass', None) @@ -128,6 +137,8 @@ class TestSuite(BaseTestSuite): try: setUpClass() except Exception as e: + if isinstance(result, _DebugResult): + raise currentClass._classSetupFailed = True className = util.strclass(currentClass) errorName = 'setUpClass (%s)' % className @@ -160,6 +171,8 @@ class TestSuite(BaseTestSuite): try: setUpModule() except Exception as e: + if isinstance(result, _DebugResult): + raise result._moduleSetUpFailed = True errorName = 'setUpModule (%s)' % currentModule self._addClassOrModuleLevelException(result, e, errorName) @@ -189,6 +202,8 @@ class TestSuite(BaseTestSuite): try: tearDownModule() except Exception as e: + if isinstance(result, _DebugResult): + raise errorName = 'tearDownModule (%s)' % previousModule self._addClassOrModuleLevelException(result, e, errorName) @@ -209,6 +224,8 @@ class TestSuite(BaseTestSuite): try: tearDownClass() except Exception as e: + if isinstance(result, _DebugResult): + raise className = util.strclass(previousClass) errorName = 'tearDownClass (%s)' % className self._addClassOrModuleLevelException(result, e, errorName) @@ -260,3 +277,10 @@ def _isnotsuite(test): except TypeError: return True return False + + +class _DebugResult(object): + "Used by the TestSuite to hold previous class when running in debug." + _previousTestClass = None + _moduleSetUpFailed = False + shouldStop = False diff --git a/Lib/unittest/test/test_runner.py b/Lib/unittest/test/test_runner.py index a7bd1a3..25f7541 100644 --- a/Lib/unittest/test/test_runner.py +++ b/Lib/unittest/test/test_runner.py @@ -110,6 +110,31 @@ class TestCleanUp(unittest.TestCase): test.run(result) self.assertEqual(ordering, ['setUp', 'cleanup1']) + def testTestCaseDebugExecutesCleanups(self): + ordering = [] + + class TestableTest(unittest.TestCase): + def setUp(self): + ordering.append('setUp') + self.addCleanup(cleanup1) + + def testNothing(self): + ordering.append('test') + + def tearDown(self): + ordering.append('tearDown') + + test = TestableTest('testNothing') + + def cleanup1(): + ordering.append('cleanup1') + test.addCleanup(cleanup2) + def cleanup2(): + ordering.append('cleanup2') + + test.debug() + self.assertEqual(ordering, ['setUp', 'test', 'tearDown', 'cleanup1', 'cleanup2']) + class Test_TextTestRunner(unittest.TestCase): """Tests for TextTestRunner.""" diff --git a/Lib/unittest/test/test_setups.py b/Lib/unittest/test/test_setups.py index 3f2994b..2ea4557 100644 --- a/Lib/unittest/test/test_setups.py +++ b/Lib/unittest/test/test_setups.py @@ -438,6 +438,68 @@ class TestSetups(unittest.TestCase): skipped = result.skipped[0][0] self.assertEqual(str(skipped), 'setUpModule (Module)') + def test_suite_debug_executes_setups_and_teardowns(self): + ordering = [] + + class Module(object): + @staticmethod + def setUpModule(): + ordering.append('setUpModule') + @staticmethod + def tearDownModule(): + ordering.append('tearDownModule') + + class Test(unittest.TestCase): + @classmethod + def setUpClass(cls): + ordering.append('setUpClass') + @classmethod + def tearDownClass(cls): + ordering.append('tearDownClass') + def test_something(self): + ordering.append('test_something') + + Test.__module__ = 'Module' + sys.modules['Module'] = Module + + suite = unittest.defaultTestLoader.loadTestsFromTestCase(Test) + suite.debug() + expectedOrder = ['setUpModule', 'setUpClass', 'test_something', 'tearDownClass', 'tearDownModule'] + self.assertEqual(ordering, expectedOrder) + + def test_suite_debug_propagates_exceptions(self): + class Module(object): + @staticmethod + def setUpModule(): + if phase == 0: + raise Exception('setUpModule') + @staticmethod + def tearDownModule(): + if phase == 1: + raise Exception('tearDownModule') + + class Test(unittest.TestCase): + @classmethod + def setUpClass(cls): + if phase == 2: + raise Exception('setUpClass') + @classmethod + def tearDownClass(cls): + if phase == 3: + raise Exception('tearDownClass') + def test_something(self): + if phase == 4: + raise Exception('test_something') + + Test.__module__ = 'Module' + sys.modules['Module'] = Module + + suite = unittest.defaultTestLoader.loadTestsFromTestCase(Test) + + messages = ('setUpModule', 'tearDownModule', 'setUpClass', 'tearDownClass', 'test_something') + for phase, msg in enumerate(messages): + with self.assertRaisesRegexp(Exception, msg): + suite.debug() if __name__ == '__main__': unittest.main() |