bpo-24412: Adds cleanUps for setUpClass and setUpModule. (GH-9190)
This commit is contained in:
parent
49fa4a9f1e
commit
0f221d09ca
|
@ -1448,6 +1448,39 @@ Test cases
|
|||
|
||||
.. versionadded:: 3.1
|
||||
|
||||
.. classmethod:: addClassCleanup(function, *args, **kwargs)
|
||||
|
||||
Add a function to be called after :meth:`tearDownClass` to cleanup
|
||||
resources used during the test class. Functions will be called in reverse
|
||||
order to the order they are added (:abbr:`LIFO (last-in, first-out)`).
|
||||
They are called with any arguments and keyword arguments passed into
|
||||
:meth:`addClassCleanup` when they are added.
|
||||
|
||||
If :meth:`setUpClass` fails, meaning that :meth:`tearDownClass` is not
|
||||
called, then any cleanup functions added will still be called.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. classmethod:: doClassCleanups()
|
||||
|
||||
This method is called unconditionally after :meth:`tearDownClass`, or
|
||||
after :meth:`setUpClass` if :meth:`setUpClass` raises an exception.
|
||||
|
||||
It is responsible for calling all the cleanup functions added by
|
||||
:meth:`addCleanupClass`. If you need cleanup functions to be called
|
||||
*prior* to :meth:`tearDownClass` then you can call
|
||||
:meth:`doCleanupsClass` yourself.
|
||||
|
||||
:meth:`doCleanupsClass` pops methods off the stack of cleanup
|
||||
functions one at a time, so it can be called at any time.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.. class:: FunctionTestCase(testFunc, setUp=None, tearDown=None, description=None)
|
||||
|
||||
|
@ -2268,6 +2301,38 @@ module will be run and the ``tearDownModule`` will not be run. If the exception
|
|||
:exc:`SkipTest` exception then the module will be reported as having been skipped
|
||||
instead of as an error.
|
||||
|
||||
To add cleanup code that must be run even in the case of an exception, use
|
||||
``addModuleCleanup``:
|
||||
|
||||
|
||||
.. function:: addModuleCleanup(function, *args, **kwargs)
|
||||
|
||||
Add a function to be called after :func:`tearDownModule` to cleanup
|
||||
resources used during the test class. Functions will be called in reverse
|
||||
order to the order they are added (:abbr:`LIFO (last-in, first-out)`).
|
||||
They are called with any arguments and keyword arguments passed into
|
||||
:meth:`addModuleCleanup` when they are added.
|
||||
|
||||
If :meth:`setUpModule` fails, meaning that :func:`tearDownModule` is not
|
||||
called, then any cleanup functions added will still be called.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. function:: doModuleCleanups()
|
||||
|
||||
This function is called unconditionally after :func:`tearDownModule`, or
|
||||
after :func:`setUpModule` if :func:`setUpModule` raises an exception.
|
||||
|
||||
It is responsible for calling all the cleanup functions added by
|
||||
:func:`addCleanupModule`. If you need cleanup functions to be called
|
||||
*prior* to :func:`tearDownModule` then you can call
|
||||
:func:`doModuleCleanups` yourself.
|
||||
|
||||
:func:`doModuleCleanups` pops methods off the stack of cleanup
|
||||
functions one at a time, so it can be called at any time.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
Signal Handling
|
||||
---------------
|
||||
|
|
|
@ -233,6 +233,15 @@ unicodedata
|
|||
is in a specific normal form. (Contributed by Max Belanger and David Euresti in
|
||||
:issue:`32285`).
|
||||
|
||||
unittest
|
||||
--------
|
||||
|
||||
* Added :func:`~unittest.addModuleCleanup()` and
|
||||
:meth:`~unittest.TestCase.addClassCleanup()` to unittest to support
|
||||
cleanups for :func:`~unittest.setUpModule()` and
|
||||
:meth:`~unittest.TestCase.setUpClass()`.
|
||||
(Contributed by Lisa Roach in :issue:`24412`.)
|
||||
|
||||
venv
|
||||
----
|
||||
|
||||
|
|
|
@ -48,7 +48,8 @@ __all__ = ['TestResult', 'TestCase', 'TestSuite',
|
|||
'TextTestRunner', 'TestLoader', 'FunctionTestCase', 'main',
|
||||
'defaultTestLoader', 'SkipTest', 'skip', 'skipIf', 'skipUnless',
|
||||
'expectedFailure', 'TextTestResult', 'installHandler',
|
||||
'registerResult', 'removeResult', 'removeHandler']
|
||||
'registerResult', 'removeResult', 'removeHandler',
|
||||
'addModuleCleanup']
|
||||
|
||||
# Expose obsolete functions for backwards compatibility
|
||||
__all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases'])
|
||||
|
@ -56,8 +57,8 @@ __all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases'])
|
|||
__unittest = True
|
||||
|
||||
from .result import TestResult
|
||||
from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf,
|
||||
skipUnless, expectedFailure)
|
||||
from .case import (addModuleCleanup, TestCase, FunctionTestCase, SkipTest, skip,
|
||||
skipIf, skipUnless, expectedFailure)
|
||||
from .suite import BaseTestSuite, TestSuite
|
||||
from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames,
|
||||
findTestCases)
|
||||
|
|
|
@ -84,6 +84,30 @@ class _Outcome(object):
|
|||
def _id(obj):
|
||||
return obj
|
||||
|
||||
|
||||
_module_cleanups = []
|
||||
def addModuleCleanup(function, *args, **kwargs):
|
||||
"""Same as addCleanup, except the cleanup items are called even if
|
||||
setUpModule fails (unlike tearDownModule)."""
|
||||
_module_cleanups.append((function, args, kwargs))
|
||||
|
||||
|
||||
def doModuleCleanups():
|
||||
"""Execute all module cleanup functions. Normally called for you after
|
||||
tearDownModule."""
|
||||
exceptions = []
|
||||
while _module_cleanups:
|
||||
function, args, kwargs = _module_cleanups.pop()
|
||||
try:
|
||||
function(*args, **kwargs)
|
||||
except Exception as exc:
|
||||
exceptions.append(exc)
|
||||
if exceptions:
|
||||
# Swallows all but first exception. If a multi-exception handler
|
||||
# gets written we should use that here instead.
|
||||
raise exceptions[0]
|
||||
|
||||
|
||||
def skip(reason):
|
||||
"""
|
||||
Unconditionally skip a test.
|
||||
|
@ -390,6 +414,8 @@ class TestCase(object):
|
|||
|
||||
_classSetupFailed = False
|
||||
|
||||
_class_cleanups = []
|
||||
|
||||
def __init__(self, methodName='runTest'):
|
||||
"""Create an instance of the class that will use the named test
|
||||
method when executed. Raises a ValueError if the instance does
|
||||
|
@ -445,6 +471,12 @@ class TestCase(object):
|
|||
Cleanup items are called even if setUp fails (unlike tearDown)."""
|
||||
self._cleanups.append((function, args, kwargs))
|
||||
|
||||
@classmethod
|
||||
def addClassCleanup(cls, function, *args, **kwargs):
|
||||
"""Same as addCleanup, except the cleanup items are called even if
|
||||
setUpClass fails (unlike tearDownClass)."""
|
||||
cls._class_cleanups.append((function, args, kwargs))
|
||||
|
||||
def setUp(self):
|
||||
"Hook method for setting up the test fixture before exercising it."
|
||||
pass
|
||||
|
@ -651,9 +683,21 @@ class TestCase(object):
|
|||
function(*args, **kwargs)
|
||||
|
||||
# return this for backwards compatibility
|
||||
# even though we no longer us it internally
|
||||
# even though we no longer use it internally
|
||||
return outcome.success
|
||||
|
||||
@classmethod
|
||||
def doClassCleanups(cls):
|
||||
"""Execute all class cleanup functions. Normally called for you after
|
||||
tearDownClass."""
|
||||
cls.tearDown_exceptions = []
|
||||
while cls._class_cleanups:
|
||||
function, args, kwargs = cls._class_cleanups.pop()
|
||||
try:
|
||||
function(*args, **kwargs)
|
||||
except Exception as exc:
|
||||
cls.tearDown_exceptions.append(sys.exc_info())
|
||||
|
||||
def __call__(self, *args, **kwds):
|
||||
return self.run(*args, **kwds)
|
||||
|
||||
|
|
|
@ -166,10 +166,18 @@ class TestSuite(BaseTestSuite):
|
|||
raise
|
||||
currentClass._classSetupFailed = True
|
||||
className = util.strclass(currentClass)
|
||||
errorName = 'setUpClass (%s)' % className
|
||||
self._addClassOrModuleLevelException(result, e, errorName)
|
||||
self._createClassOrModuleLevelException(result, e,
|
||||
'setUpClass',
|
||||
className)
|
||||
finally:
|
||||
_call_if_exists(result, '_restoreStdout')
|
||||
if currentClass._classSetupFailed is True:
|
||||
currentClass.doClassCleanups()
|
||||
if len(currentClass.tearDown_exceptions) > 0:
|
||||
for exc in currentClass.tearDown_exceptions:
|
||||
self._createClassOrModuleLevelException(
|
||||
result, exc[1], 'setUpClass', className,
|
||||
info=exc)
|
||||
|
||||
def _get_previous_module(self, result):
|
||||
previousModule = None
|
||||
|
@ -199,21 +207,37 @@ class TestSuite(BaseTestSuite):
|
|||
try:
|
||||
setUpModule()
|
||||
except Exception as e:
|
||||
try:
|
||||
case.doModuleCleanups()
|
||||
except Exception as exc:
|
||||
self._createClassOrModuleLevelException(result, exc,
|
||||
'setUpModule',
|
||||
currentModule)
|
||||
if isinstance(result, _DebugResult):
|
||||
raise
|
||||
result._moduleSetUpFailed = True
|
||||
errorName = 'setUpModule (%s)' % currentModule
|
||||
self._addClassOrModuleLevelException(result, e, errorName)
|
||||
self._createClassOrModuleLevelException(result, e,
|
||||
'setUpModule',
|
||||
currentModule)
|
||||
finally:
|
||||
_call_if_exists(result, '_restoreStdout')
|
||||
|
||||
def _addClassOrModuleLevelException(self, result, exception, errorName):
|
||||
def _createClassOrModuleLevelException(self, result, exc, method_name,
|
||||
parent, info=None):
|
||||
errorName = f'{method_name} ({parent})'
|
||||
self._addClassOrModuleLevelException(result, exc, errorName, info)
|
||||
|
||||
def _addClassOrModuleLevelException(self, result, exception, errorName,
|
||||
info=None):
|
||||
error = _ErrorHolder(errorName)
|
||||
addSkip = getattr(result, 'addSkip', None)
|
||||
if addSkip is not None and isinstance(exception, case.SkipTest):
|
||||
addSkip(error, str(exception))
|
||||
else:
|
||||
result.addError(error, sys.exc_info())
|
||||
if not info:
|
||||
result.addError(error, sys.exc_info())
|
||||
else:
|
||||
result.addError(error, info)
|
||||
|
||||
def _handleModuleTearDown(self, result):
|
||||
previousModule = self._get_previous_module(result)
|
||||
|
@ -235,10 +259,17 @@ class TestSuite(BaseTestSuite):
|
|||
except Exception as e:
|
||||
if isinstance(result, _DebugResult):
|
||||
raise
|
||||
errorName = 'tearDownModule (%s)' % previousModule
|
||||
self._addClassOrModuleLevelException(result, e, errorName)
|
||||
self._createClassOrModuleLevelException(result, e,
|
||||
'tearDownModule',
|
||||
previousModule)
|
||||
finally:
|
||||
_call_if_exists(result, '_restoreStdout')
|
||||
try:
|
||||
case.doModuleCleanups()
|
||||
except Exception as e:
|
||||
self._createClassOrModuleLevelException(result, e,
|
||||
'tearDownModule',
|
||||
previousModule)
|
||||
|
||||
def _tearDownPreviousClass(self, test, result):
|
||||
previousClass = getattr(result, '_previousTestClass', None)
|
||||
|
@ -261,10 +292,19 @@ class TestSuite(BaseTestSuite):
|
|||
if isinstance(result, _DebugResult):
|
||||
raise
|
||||
className = util.strclass(previousClass)
|
||||
errorName = 'tearDownClass (%s)' % className
|
||||
self._addClassOrModuleLevelException(result, e, errorName)
|
||||
self._createClassOrModuleLevelException(result, e,
|
||||
'tearDownClass',
|
||||
className)
|
||||
finally:
|
||||
_call_if_exists(result, '_restoreStdout')
|
||||
previousClass.doClassCleanups()
|
||||
if len(previousClass.tearDown_exceptions) > 0:
|
||||
for exc in previousClass.tearDown_exceptions:
|
||||
className = util.strclass(previousClass)
|
||||
self._createClassOrModuleLevelException(result, exc[1],
|
||||
'tearDownClass',
|
||||
className,
|
||||
info=exc)
|
||||
|
||||
|
||||
class _ErrorHolder(object):
|
||||
|
|
|
@ -11,8 +11,41 @@ from unittest.test.support import (LoggingResult,
|
|||
ResultWithNoStartTestRunStopTestRun)
|
||||
|
||||
|
||||
class TestCleanUp(unittest.TestCase):
|
||||
def resultFactory(*_):
|
||||
return unittest.TestResult()
|
||||
|
||||
|
||||
def getRunner():
|
||||
return unittest.TextTestRunner(resultclass=resultFactory,
|
||||
stream=io.StringIO())
|
||||
|
||||
|
||||
def runTests(*cases):
|
||||
suite = unittest.TestSuite()
|
||||
for case in cases:
|
||||
tests = unittest.defaultTestLoader.loadTestsFromTestCase(case)
|
||||
suite.addTests(tests)
|
||||
|
||||
runner = getRunner()
|
||||
|
||||
# creating a nested suite exposes some potential bugs
|
||||
realSuite = unittest.TestSuite()
|
||||
realSuite.addTest(suite)
|
||||
# adding empty suites to the end exposes potential bugs
|
||||
suite.addTest(unittest.TestSuite())
|
||||
realSuite.addTest(unittest.TestSuite())
|
||||
return runner.run(realSuite)
|
||||
|
||||
|
||||
def cleanup(ordering, blowUp=False):
|
||||
if not blowUp:
|
||||
ordering.append('cleanup_good')
|
||||
else:
|
||||
ordering.append('cleanup_exc')
|
||||
raise Exception('CleanUpExc')
|
||||
|
||||
|
||||
class TestCleanUp(unittest.TestCase):
|
||||
def testCleanUp(self):
|
||||
class TestableTest(unittest.TestCase):
|
||||
def testNothing(self):
|
||||
|
@ -47,10 +80,10 @@ class TestCleanUp(unittest.TestCase):
|
|||
test = TestableTest('testNothing')
|
||||
outcome = test._outcome = _Outcome()
|
||||
|
||||
exc1 = Exception('foo')
|
||||
CleanUpExc = Exception('foo')
|
||||
exc2 = Exception('bar')
|
||||
def cleanup1():
|
||||
raise exc1
|
||||
raise CleanUpExc
|
||||
|
||||
def cleanup2():
|
||||
raise exc2
|
||||
|
@ -63,7 +96,7 @@ class TestCleanUp(unittest.TestCase):
|
|||
|
||||
((_, (Type1, instance1, _)),
|
||||
(_, (Type2, instance2, _))) = reversed(outcome.errors)
|
||||
self.assertEqual((Type1, instance1), (Exception, exc1))
|
||||
self.assertEqual((Type1, instance1), (Exception, CleanUpExc))
|
||||
self.assertEqual((Type2, instance2), (Exception, exc2))
|
||||
|
||||
def testCleanupInRun(self):
|
||||
|
@ -135,6 +168,575 @@ class TestCleanUp(unittest.TestCase):
|
|||
self.assertEqual(ordering, ['setUp', 'test', 'tearDown', 'cleanup1', 'cleanup2'])
|
||||
|
||||
|
||||
class TestClassCleanup(unittest.TestCase):
|
||||
def test_addClassCleanUp(self):
|
||||
class TestableTest(unittest.TestCase):
|
||||
def testNothing(self):
|
||||
pass
|
||||
test = TestableTest('testNothing')
|
||||
self.assertEqual(test._class_cleanups, [])
|
||||
class_cleanups = []
|
||||
|
||||
def class_cleanup1(*args, **kwargs):
|
||||
class_cleanups.append((3, args, kwargs))
|
||||
|
||||
def class_cleanup2(*args, **kwargs):
|
||||
class_cleanups.append((4, args, kwargs))
|
||||
|
||||
TestableTest.addClassCleanup(class_cleanup1, 1, 2, 3,
|
||||
four='hello', five='goodbye')
|
||||
TestableTest.addClassCleanup(class_cleanup2)
|
||||
|
||||
self.assertEqual(test._class_cleanups,
|
||||
[(class_cleanup1, (1, 2, 3),
|
||||
dict(four='hello', five='goodbye')),
|
||||
(class_cleanup2, (), {})])
|
||||
|
||||
TestableTest.doClassCleanups()
|
||||
self.assertEqual(class_cleanups, [(4, (), {}), (3, (1, 2, 3),
|
||||
dict(four='hello', five='goodbye'))])
|
||||
|
||||
def test_run_class_cleanUp(self):
|
||||
ordering = []
|
||||
blowUp = True
|
||||
|
||||
class TestableTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass')
|
||||
cls.addClassCleanup(cleanup, ordering)
|
||||
if blowUp:
|
||||
raise Exception()
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass')
|
||||
|
||||
runTests(TestableTest)
|
||||
self.assertEqual(ordering, ['setUpClass', 'cleanup_good'])
|
||||
|
||||
ordering = []
|
||||
blowUp = False
|
||||
runTests(TestableTest)
|
||||
self.assertEqual(ordering,
|
||||
['setUpClass', 'test', 'tearDownClass', 'cleanup_good'])
|
||||
|
||||
def test_debug_executes_classCleanUp(self):
|
||||
ordering = []
|
||||
|
||||
class TestableTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass')
|
||||
cls.addClassCleanup(cleanup, ordering)
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass')
|
||||
|
||||
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
|
||||
suite.debug()
|
||||
self.assertEqual(ordering,
|
||||
['setUpClass', 'test', 'tearDownClass', 'cleanup_good'])
|
||||
|
||||
def test_doClassCleanups_with_errors_addClassCleanUp(self):
|
||||
class TestableTest(unittest.TestCase):
|
||||
def testNothing(self):
|
||||
pass
|
||||
|
||||
def cleanup1():
|
||||
raise Exception('cleanup1')
|
||||
|
||||
def cleanup2():
|
||||
raise Exception('cleanup2')
|
||||
|
||||
TestableTest.addClassCleanup(cleanup1)
|
||||
TestableTest.addClassCleanup(cleanup2)
|
||||
with self.assertRaises(Exception) as e:
|
||||
TestableTest.doClassCleanups()
|
||||
self.assertEquals(e, 'cleanup1')
|
||||
|
||||
def test_with_errors_addCleanUp(self):
|
||||
ordering = []
|
||||
class TestableTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass')
|
||||
cls.addClassCleanup(cleanup, ordering)
|
||||
def setUp(self):
|
||||
ordering.append('setUp')
|
||||
self.addCleanup(cleanup, ordering, blowUp=True)
|
||||
def testNothing(self):
|
||||
pass
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass')
|
||||
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(ordering,
|
||||
['setUpClass', 'setUp', 'cleanup_exc',
|
||||
'tearDownClass', 'cleanup_good'])
|
||||
|
||||
def test_run_with_errors_addClassCleanUp(self):
|
||||
ordering = []
|
||||
class TestableTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass')
|
||||
cls.addClassCleanup(cleanup, ordering, blowUp=True)
|
||||
def setUp(self):
|
||||
ordering.append('setUp')
|
||||
self.addCleanup(cleanup, ordering)
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass')
|
||||
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(ordering,
|
||||
['setUpClass', 'setUp', 'test', 'cleanup_good',
|
||||
'tearDownClass', 'cleanup_exc'])
|
||||
|
||||
def test_with_errors_in_addClassCleanup_and_setUps(self):
|
||||
ordering = []
|
||||
class_blow_up = False
|
||||
method_blow_up = False
|
||||
|
||||
class TestableTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass')
|
||||
cls.addClassCleanup(cleanup, ordering, blowUp=True)
|
||||
if class_blow_up:
|
||||
raise Exception('ClassExc')
|
||||
def setUp(self):
|
||||
ordering.append('setUp')
|
||||
if method_blow_up:
|
||||
raise Exception('MethodExc')
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass')
|
||||
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(ordering,
|
||||
['setUpClass', 'setUp', 'test',
|
||||
'tearDownClass', 'cleanup_exc'])
|
||||
ordering = []
|
||||
class_blow_up = True
|
||||
method_blow_up = False
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: ClassExc')
|
||||
self.assertEqual(result.errors[1][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(ordering,
|
||||
['setUpClass', 'cleanup_exc'])
|
||||
|
||||
ordering = []
|
||||
class_blow_up = False
|
||||
method_blow_up = True
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: MethodExc')
|
||||
self.assertEqual(result.errors[1][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(ordering,
|
||||
['setUpClass', 'setUp', 'tearDownClass',
|
||||
'cleanup_exc'])
|
||||
|
||||
|
||||
class TestModuleCleanUp(unittest.TestCase):
|
||||
def test_add_and_do_ModuleCleanup(self):
|
||||
module_cleanups = []
|
||||
|
||||
def module_cleanup1(*args, **kwargs):
|
||||
module_cleanups.append((3, args, kwargs))
|
||||
|
||||
def module_cleanup2(*args, **kwargs):
|
||||
module_cleanups.append((4, args, kwargs))
|
||||
|
||||
class Module(object):
|
||||
unittest.addModuleCleanup(module_cleanup1, 1, 2, 3,
|
||||
four='hello', five='goodbye')
|
||||
unittest.addModuleCleanup(module_cleanup2)
|
||||
|
||||
self.assertEqual(unittest.case._module_cleanups,
|
||||
[(module_cleanup1, (1, 2, 3),
|
||||
dict(four='hello', five='goodbye')),
|
||||
(module_cleanup2, (), {})])
|
||||
|
||||
unittest.case.doModuleCleanups()
|
||||
self.assertEqual(module_cleanups, [(4, (), {}), (3, (1, 2, 3),
|
||||
dict(four='hello', five='goodbye'))])
|
||||
self.assertEqual(unittest.case._module_cleanups, [])
|
||||
|
||||
def test_doModuleCleanup_with_errors_in_addModuleCleanup(self):
|
||||
module_cleanups = []
|
||||
|
||||
def module_cleanup_good(*args, **kwargs):
|
||||
module_cleanups.append((3, args, kwargs))
|
||||
|
||||
def module_cleanup_bad(*args, **kwargs):
|
||||
raise Exception('CleanUpExc')
|
||||
|
||||
class Module(object):
|
||||
unittest.addModuleCleanup(module_cleanup_good, 1, 2, 3,
|
||||
four='hello', five='goodbye')
|
||||
unittest.addModuleCleanup(module_cleanup_bad)
|
||||
self.assertEqual(unittest.case._module_cleanups,
|
||||
[(module_cleanup_good, (1, 2, 3),
|
||||
dict(four='hello', five='goodbye')),
|
||||
(module_cleanup_bad, (), {})])
|
||||
with self.assertRaises(Exception) as e:
|
||||
unittest.case.doModuleCleanups()
|
||||
self.assertEqual(str(e.exception), 'CleanUpExc')
|
||||
self.assertEqual(unittest.case._module_cleanups, [])
|
||||
|
||||
def test_run_module_cleanUp(self):
|
||||
blowUp = True
|
||||
ordering = []
|
||||
class Module(object):
|
||||
@staticmethod
|
||||
def setUpModule():
|
||||
ordering.append('setUpModule')
|
||||
unittest.addModuleCleanup(cleanup, ordering)
|
||||
if blowUp:
|
||||
raise Exception('setUpModule Exc')
|
||||
@staticmethod
|
||||
def tearDownModule():
|
||||
ordering.append('tearDownModule')
|
||||
|
||||
class TestableTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass')
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass')
|
||||
|
||||
TestableTest.__module__ = 'Module'
|
||||
sys.modules['Module'] = Module
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(ordering, ['setUpModule', 'cleanup_good'])
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: setUpModule Exc')
|
||||
|
||||
ordering = []
|
||||
blowUp = False
|
||||
runTests(TestableTest)
|
||||
self.assertEqual(ordering,
|
||||
['setUpModule', 'setUpClass', 'test', 'tearDownClass',
|
||||
'tearDownModule', 'cleanup_good'])
|
||||
self.assertEqual(unittest.case._module_cleanups, [])
|
||||
|
||||
def test_run_multiple_module_cleanUp(self):
|
||||
blowUp = True
|
||||
blowUp2 = False
|
||||
ordering = []
|
||||
class Module1(object):
|
||||
@staticmethod
|
||||
def setUpModule():
|
||||
ordering.append('setUpModule')
|
||||
unittest.addModuleCleanup(cleanup, ordering)
|
||||
if blowUp:
|
||||
raise Exception()
|
||||
@staticmethod
|
||||
def tearDownModule():
|
||||
ordering.append('tearDownModule')
|
||||
|
||||
class Module2(object):
|
||||
@staticmethod
|
||||
def setUpModule():
|
||||
ordering.append('setUpModule2')
|
||||
unittest.addModuleCleanup(cleanup, ordering)
|
||||
if blowUp2:
|
||||
raise Exception()
|
||||
@staticmethod
|
||||
def tearDownModule():
|
||||
ordering.append('tearDownModule2')
|
||||
|
||||
class TestableTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass')
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass')
|
||||
|
||||
class TestableTest2(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass2')
|
||||
def testNothing(self):
|
||||
ordering.append('test2')
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass2')
|
||||
|
||||
TestableTest.__module__ = 'Module1'
|
||||
sys.modules['Module1'] = Module1
|
||||
TestableTest2.__module__ = 'Module2'
|
||||
sys.modules['Module2'] = Module2
|
||||
runTests(TestableTest, TestableTest2)
|
||||
self.assertEqual(ordering, ['setUpModule', 'cleanup_good',
|
||||
'setUpModule2', 'setUpClass2', 'test2',
|
||||
'tearDownClass2', 'tearDownModule2',
|
||||
'cleanup_good'])
|
||||
ordering = []
|
||||
blowUp = False
|
||||
blowUp2 = True
|
||||
runTests(TestableTest, TestableTest2)
|
||||
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test',
|
||||
'tearDownClass', 'tearDownModule',
|
||||
'cleanup_good', 'setUpModule2',
|
||||
'cleanup_good'])
|
||||
|
||||
ordering = []
|
||||
blowUp = False
|
||||
blowUp2 = False
|
||||
runTests(TestableTest, TestableTest2)
|
||||
self.assertEqual(ordering,
|
||||
['setUpModule', 'setUpClass', 'test', 'tearDownClass',
|
||||
'tearDownModule', 'cleanup_good', 'setUpModule2',
|
||||
'setUpClass2', 'test2', 'tearDownClass2',
|
||||
'tearDownModule2', 'cleanup_good'])
|
||||
self.assertEqual(unittest.case._module_cleanups, [])
|
||||
|
||||
def test_debug_module_executes_cleanUp(self):
|
||||
ordering = []
|
||||
class Module(object):
|
||||
@staticmethod
|
||||
def setUpModule():
|
||||
ordering.append('setUpModule')
|
||||
unittest.addModuleCleanup(cleanup, ordering)
|
||||
@staticmethod
|
||||
def tearDownModule():
|
||||
ordering.append('tearDownModule')
|
||||
|
||||
class TestableTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass')
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass')
|
||||
|
||||
TestableTest.__module__ = 'Module'
|
||||
sys.modules['Module'] = Module
|
||||
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
|
||||
suite.debug()
|
||||
self.assertEqual(ordering,
|
||||
['setUpModule', 'setUpClass', 'test', 'tearDownClass',
|
||||
'tearDownModule', 'cleanup_good'])
|
||||
self.assertEqual(unittest.case._module_cleanups, [])
|
||||
|
||||
def test_with_errors_in_addClassCleanup(self):
|
||||
ordering = []
|
||||
|
||||
class Module(object):
|
||||
@staticmethod
|
||||
def setUpModule():
|
||||
ordering.append('setUpModule')
|
||||
unittest.addModuleCleanup(cleanup, ordering)
|
||||
@staticmethod
|
||||
def tearDownModule():
|
||||
ordering.append('tearDownModule')
|
||||
|
||||
class TestableTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass')
|
||||
cls.addClassCleanup(cleanup, ordering, blowUp=True)
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass')
|
||||
|
||||
TestableTest.__module__ = 'Module'
|
||||
sys.modules['Module'] = Module
|
||||
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(ordering,
|
||||
['setUpModule', 'setUpClass', 'test', 'tearDownClass',
|
||||
'cleanup_exc', 'tearDownModule', 'cleanup_good'])
|
||||
|
||||
def test_with_errors_in_addCleanup(self):
|
||||
ordering = []
|
||||
class Module(object):
|
||||
@staticmethod
|
||||
def setUpModule():
|
||||
ordering.append('setUpModule')
|
||||
unittest.addModuleCleanup(cleanup, ordering)
|
||||
@staticmethod
|
||||
def tearDownModule():
|
||||
ordering.append('tearDownModule')
|
||||
|
||||
class TestableTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
ordering.append('setUp')
|
||||
self.addCleanup(cleanup, ordering, blowUp=True)
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
def tearDown(self):
|
||||
ordering.append('tearDown')
|
||||
|
||||
TestableTest.__module__ = 'Module'
|
||||
sys.modules['Module'] = Module
|
||||
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(ordering,
|
||||
['setUpModule', 'setUp', 'test', 'tearDown',
|
||||
'cleanup_exc', 'tearDownModule', 'cleanup_good'])
|
||||
|
||||
def test_with_errors_in_addModuleCleanup_and_setUps(self):
|
||||
ordering = []
|
||||
module_blow_up = False
|
||||
class_blow_up = False
|
||||
method_blow_up = False
|
||||
class Module(object):
|
||||
@staticmethod
|
||||
def setUpModule():
|
||||
ordering.append('setUpModule')
|
||||
unittest.addModuleCleanup(cleanup, ordering, blowUp=True)
|
||||
if module_blow_up:
|
||||
raise Exception('ModuleExc')
|
||||
@staticmethod
|
||||
def tearDownModule():
|
||||
ordering.append('tearDownModule')
|
||||
|
||||
class TestableTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ordering.append('setUpClass')
|
||||
if class_blow_up:
|
||||
raise Exception('ClassExc')
|
||||
def setUp(self):
|
||||
ordering.append('setUp')
|
||||
if method_blow_up:
|
||||
raise Exception('MethodExc')
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
ordering.append('tearDownClass')
|
||||
|
||||
TestableTest.__module__ = 'Module'
|
||||
sys.modules['Module'] = Module
|
||||
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(ordering,
|
||||
['setUpModule', 'setUpClass', 'setUp', 'test',
|
||||
'tearDownClass', 'tearDownModule',
|
||||
'cleanup_exc'])
|
||||
|
||||
ordering = []
|
||||
module_blow_up = True
|
||||
class_blow_up = False
|
||||
method_blow_up = False
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(result.errors[1][1].splitlines()[-1],
|
||||
'Exception: ModuleExc')
|
||||
self.assertEqual(ordering, ['setUpModule', 'cleanup_exc'])
|
||||
|
||||
ordering = []
|
||||
module_blow_up = False
|
||||
class_blow_up = True
|
||||
method_blow_up = False
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: ClassExc')
|
||||
self.assertEqual(result.errors[1][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(ordering, ['setUpModule', 'setUpClass',
|
||||
'tearDownModule', 'cleanup_exc'])
|
||||
|
||||
ordering = []
|
||||
module_blow_up = False
|
||||
class_blow_up = False
|
||||
method_blow_up = True
|
||||
result = runTests(TestableTest)
|
||||
self.assertEqual(result.errors[0][1].splitlines()[-1],
|
||||
'Exception: MethodExc')
|
||||
self.assertEqual(result.errors[1][1].splitlines()[-1],
|
||||
'Exception: CleanUpExc')
|
||||
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'setUp',
|
||||
'tearDownClass', 'tearDownModule',
|
||||
'cleanup_exc'])
|
||||
|
||||
def test_module_cleanUp_with_multiple_classes(self):
|
||||
ordering =[]
|
||||
def cleanup1():
|
||||
ordering.append('cleanup1')
|
||||
|
||||
def cleanup2():
|
||||
ordering.append('cleanup2')
|
||||
|
||||
def cleanup3():
|
||||
ordering.append('cleanup3')
|
||||
|
||||
class Module(object):
|
||||
@staticmethod
|
||||
def setUpModule():
|
||||
ordering.append('setUpModule')
|
||||
unittest.addModuleCleanup(cleanup1)
|
||||
@staticmethod
|
||||
def tearDownModule():
|
||||
ordering.append('tearDownModule')
|
||||
|
||||
class TestableTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
ordering.append('setUp')
|
||||
self.addCleanup(cleanup2)
|
||||
def testNothing(self):
|
||||
ordering.append('test')
|
||||
def tearDown(self):
|
||||
ordering.append('tearDown')
|
||||
|
||||
class OtherTestableTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
ordering.append('setUp2')
|
||||
self.addCleanup(cleanup3)
|
||||
def testNothing(self):
|
||||
ordering.append('test2')
|
||||
def tearDown(self):
|
||||
ordering.append('tearDown2')
|
||||
|
||||
TestableTest.__module__ = 'Module'
|
||||
OtherTestableTest.__module__ = 'Module'
|
||||
sys.modules['Module'] = Module
|
||||
runTests(TestableTest, OtherTestableTest)
|
||||
self.assertEqual(ordering,
|
||||
['setUpModule', 'setUp', 'test', 'tearDown',
|
||||
'cleanup2', 'setUp2', 'test2', 'tearDown2',
|
||||
'cleanup3', 'tearDownModule', 'cleanup1'])
|
||||
|
||||
|
||||
class Test_TextTestRunner(unittest.TestCase):
|
||||
"""Tests for TextTestRunner."""
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Add :func:`~unittest.addModuleCleanup()` and
|
||||
:meth:`~unittest.TestCase.addClassCleanup()` to unittest to support
|
||||
cleanups for :func:`~unittest.setUpModule()` and
|
||||
:meth:`~unittest.TestCase.setUpClass()`. Patch by Lisa Roach.
|
Loading…
Reference in New Issue