Update unittest from CPython 3.10.5

This commit is contained in:
CPython developers authored and Jeong Yunwon committed 2022-07-18 00:59:52 +09:00
1 parent 760bda6c50
commit 799c78670b
31 files changed
+6053 -882

No files matched your search

+6 -6
View File
@@ -3,14 +3,14 @@ import unittest.test
from test import support
def test_main():
# used by regrtest
support.run_unittest(unittest.test.suite())
support.reap_children()
def load_tests(*_):
# used by unittest
return unittest.test.suite()
def tearDownModule():
support.reap_children()
if __name__ == "__main__":
test_main()
unittest.main()
+21 -4
View File
@@ -44,11 +44,12 @@ AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
"""
__all__ = ['TestResult', 'TestCase', 'TestSuite',
__all__ = ['TestResult', 'TestCase', 'IsolatedAsyncioTestCase', '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,14 +57,15 @@ __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)
from .main import TestProgram, main
from .runner import TextTestRunner, TextTestResult
from .signals import installHandler, registerResult, removeResult, removeHandler
# IsolatedAsyncioTestCase will be imported lazily.
# deprecated
_TextTestResult = TextTestResult
@@ -76,3 +78,18 @@ def load_tests(loader, tests, pattern):
# top level directory cached on loader instance
this_dir = os.path.dirname(__file__)
return loader.discover(start_dir=this_dir, pattern=pattern)
# Lazy import of IsolatedAsyncioTestCase from .async_case
# It imports asyncio, which is relatively heavy, but most tests
# do not need it.
def __dir__():
return globals().keys() | {'IsolatedAsyncioTestCase'}
def __getattr__(name):
if name == 'IsolatedAsyncioTestCase':
global IsolatedAsyncioTestCase
from .async_case import IsolatedAsyncioTestCase
return IsolatedAsyncioTestCase
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
+86
View File
@@ -0,0 +1,86 @@
import logging
import collections
from .case import _BaseTestCaseContext
_LoggingWatcher = collections.namedtuple("_LoggingWatcher",
["records", "output"])
class _CapturingHandler(logging.Handler):
"""
A logging handler capturing all (raw and formatted) logging output.
"""
def __init__(self):
logging.Handler.__init__(self)
self.watcher = _LoggingWatcher([], [])
def flush(self):
pass
def emit(self, record):
self.watcher.records.append(record)
msg = self.format(record)
self.watcher.output.append(msg)
class _AssertLogsContext(_BaseTestCaseContext):
"""A context manager for assertLogs() and assertNoLogs() """
LOGGING_FORMAT = "%(levelname)s:%(name)s:%(message)s"
def __init__(self, test_case, logger_name, level, no_logs):
_BaseTestCaseContext.__init__(self, test_case)
self.logger_name = logger_name
if level:
self.level = logging._nameToLevel.get(level, level)
else:
self.level = logging.INFO
self.msg = None
self.no_logs = no_logs
def __enter__(self):
if isinstance(self.logger_name, logging.Logger):
logger = self.logger = self.logger_name
else:
logger = self.logger = logging.getLogger(self.logger_name)
formatter = logging.Formatter(self.LOGGING_FORMAT)
handler = _CapturingHandler()
handler.setLevel(self.level)
handler.setFormatter(formatter)
self.watcher = handler.watcher
self.old_handlers = logger.handlers[:]
self.old_level = logger.level
self.old_propagate = logger.propagate
logger.handlers = [handler]
logger.setLevel(self.level)
logger.propagate = False
if self.no_logs:
return
return handler.watcher
def __exit__(self, exc_type, exc_value, tb):
self.logger.handlers = self.old_handlers
self.logger.propagate = self.old_propagate
self.logger.setLevel(self.old_level)
if exc_type is not None:
# let unexpected exceptions pass through
return False
if self.no_logs:
# assertNoLogs
if len(self.watcher.records) > 0:
self._raiseFailure(
"Unexpected logs found: {!r}".format(
self.watcher.output
)
)
else:
# assertLogs
if len(self.watcher.records) == 0:
self._raiseFailure(
"no logs of level {} or higher triggered on {}"
.format(logging.getLevelName(self.level), self.logger.name))
+170
View File
@@ -0,0 +1,170 @@
import asyncio
import inspect
from .case import TestCase
class IsolatedAsyncioTestCase(TestCase):
# Names intentionally have a long prefix
# to reduce a chance of clashing with user-defined attributes
# from inherited test case
#
# The class doesn't call loop.run_until_complete(self.setUp()) and family
# but uses a different approach:
# 1. create a long-running task that reads self.setUp()
# awaitable from queue along with a future
# 2. await the awaitable object passing in and set the result
# into the future object
# 3. Outer code puts the awaitable and the future object into a queue
# with waiting for the future
# The trick is necessary because every run_until_complete() call
# creates a new task with embedded ContextVar context.
# To share contextvars between setUp(), test and tearDown() we need to execute
# them inside the same task.
# Note: the test case modifies event loop policy if the policy was not instantiated
# yet.
# asyncio.get_event_loop_policy() creates a default policy on demand but never
# returns None
# I believe this is not an issue in user level tests but python itself for testing
# should reset a policy in every test module
# by calling asyncio.set_event_loop_policy(None) in tearDownModule()
def __init__(self, methodName='runTest'):
super().__init__(methodName)
self._asyncioTestLoop = None
self._asyncioCallsQueue = None
async def asyncSetUp(self):
pass
async def asyncTearDown(self):
pass
def addAsyncCleanup(self, func, /, *args, **kwargs):
# A trivial trampoline to addCleanup()
# the function exists because it has a different semantics
# and signature:
# addCleanup() accepts regular functions
# but addAsyncCleanup() accepts coroutines
#
# We intentionally don't add inspect.iscoroutinefunction() check
# for func argument because there is no way
# to check for async function reliably:
# 1. It can be "async def func()" itself
# 2. Class can implement "async def __call__()" method
# 3. Regular "def func()" that returns awaitable object
self.addCleanup(*(func, *args), **kwargs)
def _callSetUp(self):
self.setUp()
self._callAsync(self.asyncSetUp)
def _callTestMethod(self, method):
self._callMaybeAsync(method)
def _callTearDown(self):
self._callAsync(self.asyncTearDown)
self.tearDown()
def _callCleanup(self, function, *args, **kwargs):
self._callMaybeAsync(function, *args, **kwargs)
def _callAsync(self, func, /, *args, **kwargs):
assert self._asyncioTestLoop is not None, 'asyncio test loop is not initialized'
ret = func(*args, **kwargs)
assert inspect.isawaitable(ret), f'{func!r} returned non-awaitable'
fut = self._asyncioTestLoop.create_future()
self._asyncioCallsQueue.put_nowait((fut, ret))
return self._asyncioTestLoop.run_until_complete(fut)
def _callMaybeAsync(self, func, /, *args, **kwargs):
assert self._asyncioTestLoop is not None, 'asyncio test loop is not initialized'
ret = func(*args, **kwargs)
if inspect.isawaitable(ret):
fut = self._asyncioTestLoop.create_future()
self._asyncioCallsQueue.put_nowait((fut, ret))
return self._asyncioTestLoop.run_until_complete(fut)
else:
return ret
async def _asyncioLoopRunner(self, fut):
self._asyncioCallsQueue = queue = asyncio.Queue()
fut.set_result(None)
while True:
query = await queue.get()
queue.task_done()
if query is None:
return
fut, awaitable = query
try:
ret = await awaitable
if not fut.cancelled():
fut.set_result(ret)
except (SystemExit, KeyboardInterrupt):
raise
except (BaseException, asyncio.CancelledError) as ex:
if not fut.cancelled():
fut.set_exception(ex)
def _setupAsyncioLoop(self):
assert self._asyncioTestLoop is None, 'asyncio test loop already initialized'
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.set_debug(True)
self._asyncioTestLoop = loop
fut = loop.create_future()
self._asyncioCallsTask = loop.create_task(self._asyncioLoopRunner(fut))
loop.run_until_complete(fut)
def _tearDownAsyncioLoop(self):
assert self._asyncioTestLoop is not None, 'asyncio test loop is not initialized'
loop = self._asyncioTestLoop
self._asyncioTestLoop = None
self._asyncioCallsQueue.put_nowait(None)
loop.run_until_complete(self._asyncioCallsQueue.join())
try:
# cancel all tasks
to_cancel = asyncio.all_tasks(loop)
if not to_cancel:
return
for task in to_cancel:
task.cancel()
loop.run_until_complete(
asyncio.gather(*to_cancel, return_exceptions=True))
for task in to_cancel:
if task.cancelled():
continue
if task.exception() is not None:
loop.call_exception_handler({
'message': 'unhandled exception during test shutdown',
'exception': task.exception(),
'task': task,
})
# shutdown asyncgens
loop.run_until_complete(loop.shutdown_asyncgens())
finally:
# Prevent our executor environment from leaking to future tests.
loop.run_until_complete(loop.shutdown_default_executor())
asyncio.set_event_loop(None)
loop.close()
def run(self, result=None):
self._setupAsyncioLoop()
try:
return super().run(result)
finally:
self._tearDownAsyncioLoop()
def debug(self):
self._setupAsyncioLoop()
super().debug()
self._tearDownAsyncioLoop()
def __del__(self):
if self._asyncioTestLoop is not None:
self._tearDownAsyncioLoop()
+146 -143
View File
@@ -3,7 +3,6 @@
import sys
import functools
import difflib
import logging
import pprint
import re
import warnings
@@ -85,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.
@@ -99,6 +122,10 @@ def skip(reason):
test_item.__unittest_skip__ = True
test_item.__unittest_skip_why__ = reason
return test_item
if isinstance(reason, types.FunctionType):
test_item = reason
reason = ''
return decorator(test_item)
return decorator
def skipIf(condition, reason):
@@ -158,16 +185,11 @@ class _AssertRaisesBaseContext(_BaseTestCaseContext):
if not _is_subtype(self.expected, self._base_type):
raise TypeError('%s() arg 1 must be %s' %
(name, self._base_type_str))
if args and args[0] is None:
warnings.warn("callable is None",
DeprecationWarning, 3)
args = ()
if not args:
self.msg = kwargs.pop('msg', None)
if kwargs:
warnings.warn('%r is an invalid keyword argument for '
'this function' % next(iter(kwargs)),
DeprecationWarning, 3)
raise TypeError('%r is an invalid keyword argument for '
'this function' % (next(iter(kwargs)),))
return self
callable_obj, *args = args
@@ -230,7 +252,7 @@ class _AssertWarnsContext(_AssertRaisesBaseContext):
def __enter__(self):
# The __warningregistry__'s need to be in a pristine state for tests
# to work properly.
for v in sys.modules.values():
for v in list(sys.modules.values()):
if getattr(v, '__warningregistry__', None):
v.__warningregistry__ = {}
self.warnings_manager = warnings.catch_warnings(record=True)
@@ -273,74 +295,6 @@ class _AssertWarnsContext(_AssertRaisesBaseContext):
self._raiseFailure("{} not triggered".format(exc_name))
_LoggingWatcher = collections.namedtuple("_LoggingWatcher",
["records", "output"])
class _CapturingHandler(logging.Handler):
"""
A logging handler capturing all (raw and formatted) logging output.
"""
def __init__(self):
logging.Handler.__init__(self)
self.watcher = _LoggingWatcher([], [])
def flush(self):
pass
def emit(self, record):
self.watcher.records.append(record)
msg = self.format(record)
self.watcher.output.append(msg)
class _AssertLogsContext(_BaseTestCaseContext):
"""A context manager used to implement TestCase.assertLogs()."""
LOGGING_FORMAT = "%(levelname)s:%(name)s:%(message)s"
def __init__(self, test_case, logger_name, level):
_BaseTestCaseContext.__init__(self, test_case)
self.logger_name = logger_name
if level:
self.level = logging._nameToLevel.get(level, level)
else:
self.level = logging.INFO
self.msg = None
def __enter__(self):
if isinstance(self.logger_name, logging.Logger):
logger = self.logger = self.logger_name
else:
logger = self.logger = logging.getLogger(self.logger_name)
formatter = logging.Formatter(self.LOGGING_FORMAT)
handler = _CapturingHandler()
handler.setFormatter(formatter)
self.watcher = handler.watcher
self.old_handlers = logger.handlers[:]
self.old_level = logger.level
self.old_propagate = logger.propagate
logger.handlers = [handler]
logger.setLevel(self.level)
logger.propagate = False
return handler.watcher
def __exit__(self, exc_type, exc_value, tb):
self.logger.handlers = self.old_handlers
self.logger.propagate = self.old_propagate
self.logger.setLevel(self.old_level)
if exc_type is not None:
# let unexpected exceptions pass through
return False
if len(self.watcher.records) == 0:
self._raiseFailure(
"no logs of level {} or higher triggered on {}"
.format(logging.getLevelName(self.level), self.logger.name))
class _OrderedChainMap(collections.ChainMap):
def __iter__(self):
seen = set()
@@ -398,6 +352,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,7 +401,7 @@ class TestCase(object):
"""
self._type_equality_funcs[typeobj] = function
def addCleanup(self, function, *args, **kwargs):
def addCleanup(self, function, /, *args, **kwargs):
"""Add a function, with arguments, to be called when the test is
completed. Functions added are called on a LIFO basis and are
called after tearDown on test failure or success.
@@ -453,6 +409,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
@@ -483,7 +445,7 @@ class TestCase(object):
the specified test method's docstring.
"""
doc = self._testMethodDoc
return doc and doc.split("\n")[0].strip() or None
return doc.strip().split("\n")[0].strip() if doc else None
def id(self):
@@ -522,7 +484,7 @@ class TestCase(object):
case as failed but resumes execution at the end of the enclosed
block, allowing further test code to be executed.
"""
if not self._outcome.result_supports_subtests:
if self._outcome is None or not self._outcome.result_supports_subtests:
yield
return
parent = self._subtest
@@ -580,74 +542,84 @@ class TestCase(object):
else:
addUnexpectedSuccess(self)
def _callSetUp(self):
self.setUp()
def _callTestMethod(self, method):
method()
def _callTearDown(self):
self.tearDown()
def _callCleanup(self, function, /, *args, **kwargs):
function(*args, **kwargs)
def run(self, result=None):
orig_result = result
if result is None:
result = self.defaultTestResult()
startTestRun = getattr(result, 'startTestRun', None)
stopTestRun = getattr(result, 'stopTestRun', None)
if startTestRun is not None:
startTestRun()
else:
stopTestRun = None
result.startTest(self)
testMethod = getattr(self, self._testMethodName)
if (getattr(self.__class__, "__unittest_skip__", False) or
getattr(testMethod, "__unittest_skip__", False)):
# If the class or method was skipped.
try:
try:
testMethod = getattr(self, self._testMethodName)
if (getattr(self.__class__, "__unittest_skip__", False) or
getattr(testMethod, "__unittest_skip__", False)):
# If the class or method was skipped.
skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
or getattr(testMethod, '__unittest_skip_why__', ''))
self._addSkip(result, self, skip_why)
finally:
result.stopTest(self)
return
expecting_failure_method = getattr(testMethod,
"__unittest_expecting_failure__", False)
expecting_failure_class = getattr(self,
"__unittest_expecting_failure__", False)
expecting_failure = expecting_failure_class or expecting_failure_method
outcome = _Outcome(result)
try:
self._outcome = outcome
return result
expecting_failure = (
getattr(self, "__unittest_expecting_failure__", False) or
getattr(testMethod, "__unittest_expecting_failure__", False)
)
outcome = _Outcome(result)
try:
self._outcome = outcome
with outcome.testPartExecutor(self):
self.setUp()
if outcome.success:
outcome.expecting_failure = expecting_failure
with outcome.testPartExecutor(self, isTest=True):
testMethod()
outcome.expecting_failure = False
with outcome.testPartExecutor(self):
self.tearDown()
self._callSetUp()
if outcome.success:
outcome.expecting_failure = expecting_failure
with outcome.testPartExecutor(self, isTest=True):
self._callTestMethod(testMethod)
outcome.expecting_failure = False
with outcome.testPartExecutor(self):
self._callTearDown()
self.doCleanups()
for test, reason in outcome.skipped:
self._addSkip(result, test, reason)
self._feedErrorsToResult(result, outcome.errors)
if outcome.success:
if expecting_failure:
if outcome.expectedFailure:
self._addExpectedFailure(result, outcome.expectedFailure)
self.doCleanups()
for test, reason in outcome.skipped:
self._addSkip(result, test, reason)
self._feedErrorsToResult(result, outcome.errors)
if outcome.success:
if expecting_failure:
if outcome.expectedFailure:
self._addExpectedFailure(result, outcome.expectedFailure)
else:
self._addUnexpectedSuccess(result)
else:
self._addUnexpectedSuccess(result)
else:
result.addSuccess(self)
return result
result.addSuccess(self)
return result
finally:
# explicitly break reference cycles:
# outcome.errors -> frame -> outcome -> outcome.errors
# outcome.expectedFailure -> frame -> outcome -> outcome.expectedFailure
outcome.errors.clear()
outcome.expectedFailure = None
# clear the outcome, no more needed
self._outcome = None
finally:
result.stopTest(self)
if orig_result is None:
stopTestRun = getattr(result, 'stopTestRun', None)
if stopTestRun is not None:
stopTestRun()
# explicitly break reference cycles:
# outcome.errors -> frame -> outcome -> outcome.errors
# outcome.expectedFailure -> frame -> outcome -> outcome.expectedFailure
outcome.errors.clear()
outcome.expectedFailure = None
# clear the outcome, no more needed
self._outcome = None
if stopTestRun is not None:
stopTestRun()
def doCleanups(self):
"""Execute all cleanup functions. Normally called for you after
@@ -656,23 +628,43 @@ class TestCase(object):
while self._cleanups:
function, args, kwargs = self._cleanups.pop()
with outcome.testPartExecutor(self):
function(*args, **kwargs)
self._callCleanup(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:
cls.tearDown_exceptions.append(sys.exc_info())
def __call__(self, *args, **kwds):
return self.run(*args, **kwds)
def debug(self):
"""Run the test without collecting errors in a TestResult"""
self.setUp()
getattr(self, self._testMethodName)()
self.tearDown()
testMethod = getattr(self, self._testMethodName)
if (getattr(self.__class__, "__unittest_skip__", False) or
getattr(testMethod, "__unittest_skip__", False)):
# If the class or method was skipped.
skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
or getattr(testMethod, '__unittest_skip_why__', ''))
raise SkipTest(skip_why)
self._callSetUp()
self._callTestMethod(testMethod)
self._callTearDown()
while self._cleanups:
function, args, kwargs = self._cleanups.pop(-1)
function(*args, **kwargs)
function, args, kwargs = self._cleanups.pop()
self._callCleanup(function, *args, **kwargs)
def skipTest(self, reason):
"""Skip this test."""
@@ -799,7 +791,18 @@ class TestCase(object):
self.assertEqual(cm.output, ['INFO:foo:first message',
'ERROR:foo.bar:second message'])
"""
return _AssertLogsContext(self, logger, level)
# Lazy import to avoid importing logging if it is not needed.
from ._log import _AssertLogsContext
return _AssertLogsContext(self, logger, level, no_logs=False)
def assertNoLogs(self, logger=None, level=None):
""" Fail unless no log messages of level *level* or higher are emitted
on *logger_name* or its children.
This method must be used as a context manager.
"""
from ._log import _AssertLogsContext
return _AssertLogsContext(self, logger, level, no_logs=True)
def _getAssertEqualityFunc(self, first, second):
"""Get a detailed comparison function for the types of the two args.
@@ -1143,7 +1146,8 @@ class TestCase(object):
def assertDictContainsSubset(self, subset, dictionary, msg=None):
"""Checks whether dictionary is a superset of subset."""
warnings.warn('assertDictContainsSubset is deprecated',
DeprecationWarning)
DeprecationWarning,
stacklevel=2)
missing = []
mismatched = []
for key, value in subset.items():
@@ -1170,9 +1174,8 @@ class TestCase(object):
def assertCountEqual(self, first, second, msg=None):
"""An unordered sequence comparison asserting that the same elements,
regardless of order. If the same element occurs more than once,
it verifies that the elements occur the same number of times.
"""Asserts that two iterables have the same elements, the same number of
times, without regard to order.
self.assertEqual(Counter(list(first)),
Counter(list(second)))
+3 -1
View File
@@ -229,7 +229,9 @@ class TestLoader(object):
testFunc = getattr(testCaseClass, attrname)
if not callable(testFunc):
return False
fullName = '%s.%s' % (testCaseClass.__module__, testFunc.__qualname__)
fullName = f'%s.%s.%s' % (
testCaseClass.__module__, testCaseClass.__qualname__, attrname
)
return self.testNamePatterns is None or \
any(fnmatchcase(fullName, pattern) for pattern in self.testNamePatterns)
testFnNames = list(filter(shouldIncludeMethod, dir(testCaseClass)))
+1 -1
View File
@@ -39,7 +39,7 @@ def _convert_name(name):
name = rel_path
# on Windows both '\' and '/' are used as path
# separators. Better to replace both than rely on os.path.sep
return name[:-3].replace('\\', '.').replace('/', '.')
return os.path.normpath(name)[:-3].replace('\\', '.').replace('/', '.')
return name
def _convert_names(names):
+835 -327
View File
File diff suppressed because it is too large. Load diff
+41 -15
View File
@@ -161,7 +161,7 @@ class TestResult(object):
"""Tells whether or not this result was a success."""
# The hasattr check is for test_result's OldResult test. That
# way this method works on objects that lack the attribute.
# (where would such result intances come from? old stored pickles?)
# (where would such result instances come from? old stored pickles?)
return ((len(self.failures) == len(self.errors) == 0) and
(not hasattr(self, 'unexpectedSuccesses') or
len(self.unexpectedSuccesses) == 0))
@@ -173,17 +173,10 @@ class TestResult(object):
def _exc_info_to_string(self, err, test):
"""Converts a sys.exc_info()-style tuple of values into a string."""
exctype, value, tb = err
# Skip test runner traceback levels
while tb and self._is_relevant_tb_level(tb):
tb = tb.tb_next
if exctype is test.failureException:
# Skip assert*() traceback levels
length = self._count_relevant_tb_levels(tb)
else:
length = None
tb = self._clean_tracebacks(exctype, value, tb, test)
tb_e = traceback.TracebackException(
exctype, value, tb, limit=length, capture_locals=self.tb_locals)
exctype, value, tb,
capture_locals=self.tb_locals, compact=True)
msgLines = list(tb_e.format())
if self.buffer:
@@ -199,16 +192,49 @@ class TestResult(object):
msgLines.append(STDERR_LINE % error)
return ''.join(msgLines)
def _clean_tracebacks(self, exctype, value, tb, test):
ret = None
first = True
excs = [(exctype, value, tb)]
while excs:
(exctype, value, tb) = excs.pop()
# Skip test runner traceback levels
while tb and self._is_relevant_tb_level(tb):
tb = tb.tb_next
# Skip assert*() traceback levels
if exctype is test.failureException:
self._remove_unittest_tb_frames(tb)
if first:
ret = tb
first = False
else:
value.__traceback__ = tb
if value is not None:
for c in (value.__cause__, value.__context__):
if c is not None:
excs.append((type(c), c, c.__traceback__))
return ret
def _is_relevant_tb_level(self, tb):
return '__unittest' in tb.tb_frame.f_globals
def _count_relevant_tb_levels(self, tb):
length = 0
def _remove_unittest_tb_frames(self, tb):
'''Truncates usercode tb at the first unittest frame.
If the first frame of the traceback is in user code,
the prefix up to the first unittest frame is returned.
If the first frame is already in the unittest module,
the traceback is not modified.
'''
prev = None
while tb and not self._is_relevant_tb_level(tb):
length += 1
prev = tb
tb = tb.tb_next
return length
if prev is not None:
prev.tb_next = None
def __repr__(self):
return ("<%s run=%i errors=%i failures=%i>" %
+11 -2
View File
@@ -59,6 +59,7 @@ class TextTestResult(result.TestResult):
super(TextTestResult, self).addSuccess(test)
if self.showAll:
self.stream.writeln("ok")
self.stream.flush()
elif self.dots:
self.stream.write('.')
self.stream.flush()
@@ -67,6 +68,7 @@ class TextTestResult(result.TestResult):
super(TextTestResult, self).addError(test, err)
if self.showAll:
self.stream.writeln("ERROR")
self.stream.flush()
elif self.dots:
self.stream.write('E')
self.stream.flush()
@@ -75,6 +77,7 @@ class TextTestResult(result.TestResult):
super(TextTestResult, self).addFailure(test, err)
if self.showAll:
self.stream.writeln("FAIL")
self.stream.flush()
elif self.dots:
self.stream.write('F')
self.stream.flush()
@@ -83,6 +86,7 @@ class TextTestResult(result.TestResult):
super(TextTestResult, self).addSkip(test, reason)
if self.showAll:
self.stream.writeln("skipped {0!r}".format(reason))
self.stream.flush()
elif self.dots:
self.stream.write("s")
self.stream.flush()
@@ -91,6 +95,7 @@ class TextTestResult(result.TestResult):
super(TextTestResult, self).addExpectedFailure(test, err)
if self.showAll:
self.stream.writeln("expected failure")
self.stream.flush()
elif self.dots:
self.stream.write("x")
self.stream.flush()
@@ -99,6 +104,7 @@ class TextTestResult(result.TestResult):
super(TextTestResult, self).addUnexpectedSuccess(test)
if self.showAll:
self.stream.writeln("unexpected success")
self.stream.flush()
elif self.dots:
self.stream.write("u")
self.stream.flush()
@@ -106,6 +112,7 @@ class TextTestResult(result.TestResult):
def printErrors(self):
if self.dots or self.showAll:
self.stream.writeln()
self.stream.flush()
self.printErrorList('ERROR', self.errors)
self.printErrorList('FAIL', self.failures)
@@ -115,6 +122,7 @@ class TextTestResult(result.TestResult):
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
self.stream.writeln(self.separator2)
self.stream.writeln("%s" % err)
self.stream.flush()
class TextTestRunner(object):
@@ -168,7 +176,7 @@ class TextTestRunner(object):
warnings.filterwarnings('module',
category=DeprecationWarning,
message=r'Please use assert\w+ instead.')
startTime = time.time()
startTime = time.perf_counter()
startTestRun = getattr(result, 'startTestRun', None)
if startTestRun is not None:
startTestRun()
@@ -178,7 +186,7 @@ class TextTestRunner(object):
stopTestRun = getattr(result, 'stopTestRun', None)
if stopTestRun is not None:
stopTestRun()
stopTime = time.time()
stopTime = time.perf_counter()
timeTaken = stopTime - startTime
result.printErrors()
if hasattr(result, 'separator2'):
@@ -218,4 +226,5 @@ class TextTestRunner(object):
self.stream.writeln(" (%s)" % (", ".join(infos),))
else:
self.stream.write("\n")
self.stream.flush()
return result
+96 -38
View File
@@ -149,6 +149,7 @@ class TestSuite(BaseTestSuite):
if getattr(currentClass, "__unittest_skip__", False):
return
failed = False
try:
currentClass._classSetupFailed = False
except TypeError:
@@ -157,17 +158,30 @@ class TestSuite(BaseTestSuite):
pass
setUpClass = getattr(currentClass, 'setUpClass', None)
doClassCleanups = getattr(currentClass, 'doClassCleanups', None)
if setUpClass is not None:
_call_if_exists(result, '_setupStdout')
try:
setUpClass()
except Exception as e:
if isinstance(result, _DebugResult):
raise
currentClass._classSetupFailed = True
className = util.strclass(currentClass)
errorName = 'setUpClass (%s)' % className
self._addClassOrModuleLevelException(result, e, errorName)
try:
setUpClass()
except Exception as e:
if isinstance(result, _DebugResult):
raise
failed = True
try:
currentClass._classSetupFailed = True
except TypeError:
pass
className = util.strclass(currentClass)
self._createClassOrModuleLevelException(result, e,
'setUpClass',
className)
if failed and doClassCleanups is not None:
doClassCleanups()
for exc_info in currentClass.tearDown_exceptions:
self._createClassOrModuleLevelException(
result, exc_info[1], 'setUpClass', className,
info=exc_info)
finally:
_call_if_exists(result, '_restoreStdout')
@@ -197,23 +211,41 @@ class TestSuite(BaseTestSuite):
if setUpModule is not None:
_call_if_exists(result, '_setupStdout')
try:
setUpModule()
except Exception as e:
if isinstance(result, _DebugResult):
raise
result._moduleSetUpFailed = True
errorName = 'setUpModule (%s)' % currentModule
self._addClassOrModuleLevelException(result, e, errorName)
try:
setUpModule()
except Exception as e:
if isinstance(result, _DebugResult):
raise
result._moduleSetUpFailed = True
self._createClassOrModuleLevelException(result, e,
'setUpModule',
currentModule)
if result._moduleSetUpFailed:
try:
case.doModuleCleanups()
except Exception as e:
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)
@@ -227,23 +259,33 @@ class TestSuite(BaseTestSuite):
except KeyError:
return
tearDownModule = getattr(module, 'tearDownModule', None)
if tearDownModule is not None:
_call_if_exists(result, '_setupStdout')
_call_if_exists(result, '_setupStdout')
try:
tearDownModule = getattr(module, 'tearDownModule', None)
if tearDownModule is not None:
try:
tearDownModule()
except Exception as e:
if isinstance(result, _DebugResult):
raise
self._createClassOrModuleLevelException(result, e,
'tearDownModule',
previousModule)
try:
tearDownModule()
case.doModuleCleanups()
except Exception as e:
if isinstance(result, _DebugResult):
raise
errorName = 'tearDownModule (%s)' % previousModule
self._addClassOrModuleLevelException(result, e, errorName)
finally:
_call_if_exists(result, '_restoreStdout')
self._createClassOrModuleLevelException(result, e,
'tearDownModule',
previousModule)
finally:
_call_if_exists(result, '_restoreStdout')
def _tearDownPreviousClass(self, test, result):
previousClass = getattr(result, '_previousTestClass', None)
currentClass = test.__class__
if currentClass == previousClass:
if currentClass == previousClass or previousClass is None:
return
if getattr(previousClass, '_classSetupFailed', False):
return
@@ -253,18 +295,34 @@ class TestSuite(BaseTestSuite):
return
tearDownClass = getattr(previousClass, 'tearDownClass', None)
if tearDownClass is not None:
_call_if_exists(result, '_setupStdout')
try:
tearDownClass()
except Exception as e:
if isinstance(result, _DebugResult):
raise
className = util.strclass(previousClass)
errorName = 'tearDownClass (%s)' % className
self._addClassOrModuleLevelException(result, e, errorName)
finally:
_call_if_exists(result, '_restoreStdout')
doClassCleanups = getattr(previousClass, 'doClassCleanups', None)
if tearDownClass is None and doClassCleanups is None:
return
_call_if_exists(result, '_setupStdout')
try:
if tearDownClass is not None:
try:
tearDownClass()
except Exception as e:
if isinstance(result, _DebugResult):
raise
className = util.strclass(previousClass)
self._createClassOrModuleLevelException(result, e,
'tearDownClass',
className)
if doClassCleanups is not None:
doClassCleanups()
for exc_info in previousClass.tearDown_exceptions:
if isinstance(result, _DebugResult):
raise exc_info[1]
className = util.strclass(previousClass)
self._createClassOrModuleLevelException(result, exc_info[1],
'tearDownClass',
className,
info=exc_info)
finally:
_call_if_exists(result, '_restoreStdout')
class _ErrorHolder(object):
+3
View File
@@ -2,6 +2,7 @@ import datetime
import warnings
import weakref
import unittest
from test.support import gc_collect
from itertools import product
@@ -124,8 +125,10 @@ class Test_Assertions(unittest.TestCase):
self.foo()
Foo("test_functional").run()
gc_collect() # For PyPy or other GCs.
self.assertIsNone(wr())
Foo("test_with").run()
gc_collect() # For PyPy or other GCs.
self.assertIsNone(wr())
def testAssertNotRegex(self):
+346
View File
@@ -0,0 +1,346 @@
import asyncio
import unittest
from test import support
class MyException(Exception):
pass
def tearDownModule():
asyncio.set_event_loop_policy(None)
class TestAsyncCase(unittest.TestCase):
maxDiff = None
def tearDown(self):
# Ensure that IsolatedAsyncioTestCase instances are destroyed before
# starting a new event loop
support.gc_collect()
def test_full_cycle(self):
class Test(unittest.IsolatedAsyncioTestCase):
def setUp(self):
self.assertEqual(events, [])
events.append('setUp')
async def asyncSetUp(self):
self.assertEqual(events, ['setUp'])
events.append('asyncSetUp')
self.addAsyncCleanup(self.on_cleanup1)
async def test_func(self):
self.assertEqual(events, ['setUp',
'asyncSetUp'])
events.append('test')
self.addAsyncCleanup(self.on_cleanup2)
async def asyncTearDown(self):
self.assertEqual(events, ['setUp',
'asyncSetUp',
'test'])
events.append('asyncTearDown')
def tearDown(self):
self.assertEqual(events, ['setUp',
'asyncSetUp',
'test',
'asyncTearDown'])
events.append('tearDown')
async def on_cleanup1(self):
self.assertEqual(events, ['setUp',
'asyncSetUp',
'test',
'asyncTearDown',
'tearDown',
'cleanup2'])
events.append('cleanup1')
async def on_cleanup2(self):
self.assertEqual(events, ['setUp',
'asyncSetUp',
'test',
'asyncTearDown',
'tearDown'])
events.append('cleanup2')
events = []
test = Test("test_func")
result = test.run()
self.assertEqual(result.errors, [])
self.assertEqual(result.failures, [])
expected = ['setUp', 'asyncSetUp', 'test',
'asyncTearDown', 'tearDown', 'cleanup2', 'cleanup1']
self.assertEqual(events, expected)
events = []
test = Test("test_func")
test.debug()
self.assertEqual(events, expected)
test.doCleanups()
self.assertEqual(events, expected)
def test_exception_in_setup(self):
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
events.append('asyncSetUp')
self.addAsyncCleanup(self.on_cleanup)
raise MyException()
async def test_func(self):
events.append('test')
async def asyncTearDown(self):
events.append('asyncTearDown')
async def on_cleanup(self):
events.append('cleanup')
events = []
test = Test("test_func")
result = test.run()
self.assertEqual(events, ['asyncSetUp', 'cleanup'])
self.assertIs(result.errors[0][0], test)
self.assertIn('MyException', result.errors[0][1])
events = []
test = Test("test_func")
try:
test.debug()
except MyException:
pass
else:
self.fail('Expected a MyException exception')
self.assertEqual(events, ['asyncSetUp'])
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'cleanup'])
def test_exception_in_test(self):
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
events.append('asyncSetUp')
async def test_func(self):
events.append('test')
self.addAsyncCleanup(self.on_cleanup)
raise MyException()
async def asyncTearDown(self):
events.append('asyncTearDown')
async def on_cleanup(self):
events.append('cleanup')
events = []
test = Test("test_func")
result = test.run()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup'])
self.assertIs(result.errors[0][0], test)
self.assertIn('MyException', result.errors[0][1])
events = []
test = Test("test_func")
try:
test.debug()
except MyException:
pass
else:
self.fail('Expected a MyException exception')
self.assertEqual(events, ['asyncSetUp', 'test'])
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'test', 'cleanup'])
def test_exception_in_tear_down(self):
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
events.append('asyncSetUp')
async def test_func(self):
events.append('test')
self.addAsyncCleanup(self.on_cleanup)
async def asyncTearDown(self):
events.append('asyncTearDown')
raise MyException()
async def on_cleanup(self):
events.append('cleanup')
events = []
test = Test("test_func")
result = test.run()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup'])
self.assertIs(result.errors[0][0], test)
self.assertIn('MyException', result.errors[0][1])
events = []
test = Test("test_func")
try:
test.debug()
except MyException:
pass
else:
self.fail('Expected a MyException exception')
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown'])
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup'])
def test_exception_in_tear_clean_up(self):
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
events.append('asyncSetUp')
async def test_func(self):
events.append('test')
self.addAsyncCleanup(self.on_cleanup1)
self.addAsyncCleanup(self.on_cleanup2)
async def asyncTearDown(self):
events.append('asyncTearDown')
async def on_cleanup1(self):
events.append('cleanup1')
raise MyException('some error')
async def on_cleanup2(self):
events.append('cleanup2')
raise MyException('other error')
events = []
test = Test("test_func")
result = test.run()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup2', 'cleanup1'])
self.assertIs(result.errors[0][0], test)
self.assertIn('MyException: other error', result.errors[0][1])
self.assertIn('MyException: some error', result.errors[1][1])
events = []
test = Test("test_func")
try:
test.debug()
except MyException:
pass
else:
self.fail('Expected a MyException exception')
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup2'])
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup2', 'cleanup1'])
def test_cleanups_interleave_order(self):
events = []
class Test(unittest.IsolatedAsyncioTestCase):
async def test_func(self):
self.addAsyncCleanup(self.on_sync_cleanup, 1)
self.addAsyncCleanup(self.on_async_cleanup, 2)
self.addAsyncCleanup(self.on_sync_cleanup, 3)
self.addAsyncCleanup(self.on_async_cleanup, 4)
async def on_sync_cleanup(self, val):
events.append(f'sync_cleanup {val}')
async def on_async_cleanup(self, val):
events.append(f'async_cleanup {val}')
test = Test("test_func")
test.run()
self.assertEqual(events, ['async_cleanup 4',
'sync_cleanup 3',
'async_cleanup 2',
'sync_cleanup 1'])
def test_base_exception_from_async_method(self):
events = []
class Test(unittest.IsolatedAsyncioTestCase):
async def test_base(self):
events.append("test_base")
raise BaseException()
events.append("not it")
async def test_no_err(self):
events.append("test_no_err")
async def test_cancel(self):
raise asyncio.CancelledError()
test = Test("test_base")
output = test.run()
self.assertFalse(output.wasSuccessful())
test = Test("test_no_err")
test.run()
self.assertEqual(events, ['test_base', 'test_no_err'])
test = Test("test_cancel")
output = test.run()
self.assertFalse(output.wasSuccessful())
def test_cancellation_hanging_tasks(self):
cancelled = False
class Test(unittest.IsolatedAsyncioTestCase):
async def test_leaking_task(self):
async def coro():
nonlocal cancelled
try:
await asyncio.sleep(1)
except asyncio.CancelledError:
cancelled = True
raise
# Leave this running in the background
asyncio.create_task(coro())
test = Test("test_leaking_task")
output = test.run()
self.assertTrue(cancelled)
def test_debug_cleanup_same_loop(self):
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
async def coro():
await asyncio.sleep(0)
fut = asyncio.ensure_future(coro())
self.addAsyncCleanup(self.cleanup, fut)
events.append('asyncSetUp')
async def test_func(self):
events.append('test')
raise MyException()
async def asyncTearDown(self):
events.append('asyncTearDown')
async def cleanup(self, fut):
try:
# Raises an exception if in different loop
await asyncio.wait([fut])
events.append('cleanup')
except:
import traceback
traceback.print_exc()
raise
events = []
test = Test("test_func")
result = test.run()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup'])
self.assertIn('MyException', result.errors[0][1])
events = []
test = Test("test_func")
try:
test.debug()
except MyException:
pass
else:
self.fail('Expected a MyException exception')
self.assertEqual(events, ['asyncSetUp', 'test'])
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'test', 'cleanup'])
if __name__ == "__main__":
unittest.main()
+7 -10
View File
@@ -1,4 +1,4 @@
# import gc
import gc
import io
import os
import sys
@@ -39,16 +39,13 @@ class TestBreak(unittest.TestCase):
def testRegisterResult(self):
result = unittest.TestResult()
self.assertNotIn(result, unittest.signals._results)
unittest.registerResult(result)
for ref in unittest.signals._results:
if ref is result:
break
elif ref is not result:
self.fail("odd object in result set")
else:
self.fail("result not found")
try:
self.assertIn(result, unittest.signals._results)
finally:
unittest.removeResult(result)
def testInterruptCaught(self):
default_handler = signal.getsignal(signal.SIGINT)
+142 -14
View File
@@ -8,6 +8,7 @@ import logging
import warnings
import weakref
import inspect
import types
from copy import deepcopy
from test import support
@@ -18,7 +19,7 @@ from unittest.test.support import (
TestEquality, TestHashing, LoggingResult, LegacyLoggingResult,
ResultWithNoStartTestRunStopTestRun
)
from test.support import captured_stderr
from test.support import captured_stderr, gc_collect
log_foo = logging.getLogger('foo')
@@ -425,6 +426,20 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
expected = ['a1', 'a2', 'b1']
self.assertEqual(events, expected)
def test_subtests_debug(self):
# Test debug() with a test that uses subTest() (bpo-34900)
events = []
class Foo(unittest.TestCase):
def test_a(self):
events.append('test case')
with self.subTest():
events.append('subtest 1')
Foo('test_a').debug()
self.assertEqual(events, ['test case', 'subtest 1'])
# "This class attribute gives the exception raised by the test() method.
# If a test framework needs to use a specialized exception, possibly to
# carry additional information, it must subclass this exception in
@@ -596,6 +611,17 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
'Tests shortDescription() for a method with a longer '
'docstring.')
@unittest.skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above")
def testShortDescriptionWhitespaceTrimming(self):
"""
Tests shortDescription() whitespace is trimmed, so that the first
line of nonwhite-space text becomes the docstring.
"""
self.assertEqual(
self.shortDescription(),
'Tests shortDescription() whitespace is trimmed, so that the first')
def testAddTypeEqualityFunc(self):
class SadSnake(object):
"""Dummy class for test_addTypeEqualityFunc."""
@@ -606,7 +632,7 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
self.addTypeEqualityFunc(SadSnake, AllSnakesCreatedEqual)
self.assertEqual(s1, s2)
# No this doesn't clean up and remove the SadSnake equality func
# from this TestCase instance but since its a local nothing else
# from this TestCase instance but since it's local nothing else
# will ever notice that.
def testAssertIs(self):
@@ -682,6 +708,10 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
with self.assertRaises(self.failureException):
self.assertDictContainsSubset({'foo': one}, {'foo': '\uFFFD'})
with self.assertWarns(DeprecationWarning) as warninfo:
self.assertDictContainsSubset({}, {})
self.assertEqual(warninfo.warnings[0].filename, __file__)
def testAssertEqual(self):
equal_pairs = [
((), ()),
@@ -1222,7 +1252,7 @@ test case
with self.assertRaises(self.failureException):
self.assertRaises(ExceptionMock, lambda: 0)
# Failure when the function is None
with self.assertWarns(DeprecationWarning):
with self.assertRaises(TypeError):
self.assertRaises(ExceptionMock, None)
# Failure when another exception is raised
with self.assertRaises(ExceptionMock):
@@ -1253,8 +1283,7 @@ test case
with self.assertRaises(ExceptionMock, msg='foobar'):
pass
# Invalid keyword argument
with self.assertWarnsRegex(DeprecationWarning, 'foobar'), \
self.assertRaises(AssertionError):
with self.assertRaisesRegex(TypeError, 'foobar'):
with self.assertRaises(ExceptionMock, foobar=42):
pass
# Failure when another exception is raised
@@ -1295,7 +1324,7 @@ test case
self.assertRaisesRegex(ExceptionMock, re.compile('expect$'), Stub)
self.assertRaisesRegex(ExceptionMock, 'expect$', Stub)
with self.assertWarns(DeprecationWarning):
with self.assertRaises(TypeError):
self.assertRaisesRegex(ExceptionMock, 'expect$', None)
def testAssertNotRaisesRegex(self):
@@ -1312,8 +1341,7 @@ test case
with self.assertRaisesRegex(Exception, 'expect', msg='foobar'):
pass
# Invalid keyword argument
with self.assertWarnsRegex(DeprecationWarning, 'foobar'), \
self.assertRaises(AssertionError):
with self.assertRaisesRegex(TypeError, 'foobar'):
with self.assertRaisesRegex(Exception, 'expect', foobar=42):
pass
@@ -1329,6 +1357,20 @@ test case
pass
self.assertRaises(TypeError, self.assertWarnsRegex, MyWarn, lambda: True)
def testAssertWarnsModifySysModules(self):
# bpo-29620: handle modified sys.modules during iteration
class Foo(types.ModuleType):
@property
def __warningregistry__(self):
sys.modules['@bar@'] = 'bar'
sys.modules['@foo@'] = Foo('foo')
try:
self.assertWarns(UserWarning, warnings.warn, 'expected')
finally:
del sys.modules['@foo@']
del sys.modules['@bar@']
def testAssertRaisesRegexMismatch(self):
def Stub():
raise Exception('Unexpected')
@@ -1388,7 +1430,7 @@ test case
with self.assertRaises(self.failureException):
self.assertWarns(RuntimeWarning, lambda: 0)
# Failure when the function is None
with self.assertWarns(DeprecationWarning):
with self.assertRaises(TypeError):
self.assertWarns(RuntimeWarning, None)
# Failure when another warning is triggered
with warnings.catch_warnings():
@@ -1433,8 +1475,7 @@ test case
with self.assertWarns(RuntimeWarning, msg='foobar'):
pass
# Invalid keyword argument
with self.assertWarnsRegex(DeprecationWarning, 'foobar'), \
self.assertRaises(AssertionError):
with self.assertRaisesRegex(TypeError, 'foobar'):
with self.assertWarns(RuntimeWarning, foobar=42):
pass
# Failure when another warning is triggered
@@ -1475,7 +1516,7 @@ test case
self.assertWarnsRegex(RuntimeWarning, "o+",
lambda: 0)
# Failure when the function is None
with self.assertWarns(DeprecationWarning):
with self.assertRaises(TypeError):
self.assertWarnsRegex(RuntimeWarning, "o+", None)
# Failure when another warning is triggered
with warnings.catch_warnings():
@@ -1518,8 +1559,7 @@ test case
with self.assertWarnsRegex(RuntimeWarning, 'o+', msg='foobar'):
pass
# Invalid keyword argument
with self.assertWarnsRegex(DeprecationWarning, 'foobar'), \
self.assertRaises(AssertionError):
with self.assertRaisesRegex(TypeError, 'foobar'):
with self.assertWarnsRegex(RuntimeWarning, 'o+', foobar=42):
pass
# Failure when another warning is triggered
@@ -1639,6 +1679,18 @@ test case
with self.assertLogs(level='WARNING'):
log_foo.info("1")
def testAssertLogsFailureLevelTooHigh_FilterInRootLogger(self):
# Failure due to level too high - message propagated to root
with self.assertNoStderr():
oldLevel = log_foo.level
log_foo.setLevel(logging.INFO)
try:
with self.assertRaises(self.failureException):
with self.assertLogs(level='WARNING'):
log_foo.info("1")
finally:
log_foo.setLevel(oldLevel)
def testAssertLogsFailureMismatchingLogger(self):
# Failure due to mismatching logger (and the logged message is
# passed through)
@@ -1647,6 +1699,81 @@ test case
with self.assertLogs('foo'):
log_quux.error("1")
def testAssertLogsUnexpectedException(self):
# Check unexpected exception will go through.
with self.assertRaises(ZeroDivisionError):
with self.assertLogs():
raise ZeroDivisionError("Unexpected")
def testAssertNoLogsDefault(self):
with self.assertRaises(self.failureException) as cm:
with self.assertNoLogs():
log_foo.info("1")
log_foobar.debug("2")
self.assertEqual(
str(cm.exception),
"Unexpected logs found: ['INFO:foo:1']",
)
def testAssertNoLogsFailureFoundLogs(self):
with self.assertRaises(self.failureException) as cm:
with self.assertNoLogs():
log_quux.error("1")
log_foo.error("foo")
self.assertEqual(
str(cm.exception),
"Unexpected logs found: ['ERROR:quux:1', 'ERROR:foo:foo']",
)
def testAssertNoLogsPerLogger(self):
with self.assertNoStderr():
with self.assertLogs(log_quux):
with self.assertNoLogs(logger=log_foo):
log_quux.error("1")
def testAssertNoLogsFailurePerLogger(self):
# Failure due to unexpected logs for the given logger or its
# children.
with self.assertRaises(self.failureException) as cm:
with self.assertLogs(log_quux):
with self.assertNoLogs(logger=log_foo):
log_quux.error("1")
log_foobar.info("2")
self.assertEqual(
str(cm.exception),
"Unexpected logs found: ['INFO:foo.bar:2']",
)
def testAssertNoLogsPerLevel(self):
# Check per-level filtering
with self.assertNoStderr():
with self.assertNoLogs(level="ERROR"):
log_foo.info("foo")
log_quux.debug("1")
def testAssertNoLogsFailurePerLevel(self):
# Failure due to unexpected logs at the specified level.
with self.assertRaises(self.failureException) as cm:
with self.assertNoLogs(level="DEBUG"):
log_foo.debug("foo")
log_quux.debug("1")
self.assertEqual(
str(cm.exception),
"Unexpected logs found: ['DEBUG:foo:foo', 'DEBUG:quux:1']",
)
def testAssertNoLogsUnexpectedException(self):
# Check unexpected exception will go through.
with self.assertRaises(ZeroDivisionError):
with self.assertNoLogs():
raise ZeroDivisionError("Unexpected")
def testAssertNoLogsYieldsNone(self):
with self.assertNoLogs() as value:
pass
self.assertIsNone(value)
def testDeprecatedMethodNames(self):
"""
Test that the deprecated methods raise a DeprecationWarning. See #9424.
@@ -1828,6 +1955,7 @@ test case
for method_name in ('test1', 'test2'):
testcase = TestCase(method_name)
testcase.run()
gc_collect() # For PyPy or other GCs.
self.assertEqual(MyException.ninstance, 0)
+6
View File
@@ -724,11 +724,13 @@ class TestDiscovery(unittest.TestCase):
original_listdir = os.listdir
original_isfile = os.path.isfile
original_isdir = os.path.isdir
original_realpath = os.path.realpath
def cleanup():
os.listdir = original_listdir
os.path.isfile = original_isfile
os.path.isdir = original_isdir
os.path.realpath = original_realpath
del sys.modules['foo']
if full_path in sys.path:
sys.path.remove(full_path)
@@ -743,6 +745,10 @@ class TestDiscovery(unittest.TestCase):
os.listdir = listdir
os.path.isfile = isfile
os.path.isdir = isdir
if os.name == 'nt':
# ntpath.realpath may inject path prefixes when failing to
# resolve real files, so we substitute abspath() here instead.
os.path.realpath = os.path.abspath
return full_path
def test_detect_module_clash(self):
+16
View File
@@ -1,3 +1,4 @@
import functools
import sys
import types
import warnings
@@ -1575,5 +1576,20 @@ class Test_TestLoader(unittest.TestCase):
self.assertIs(loader.suiteClass, unittest.TestSuite)
def test_partial_functions(self):
def noop(arg):
pass
class Foo(unittest.TestCase):
pass
setattr(Foo, 'test_partial', functools.partial(noop, None))
loader = unittest.TestLoader()
test_names = ['test_partial']
self.assertEqual(loader.getTestCaseNames(Foo), test_names)
if __name__ == "__main__":
unittest.main()
+15 -7
View File
@@ -6,6 +6,7 @@ import subprocess
from test import support
import unittest
import unittest.test
from unittest.test.test_result import BufferedWriter
class Test_TestProgram(unittest.TestCase):
@@ -57,9 +58,9 @@ class Test_TestProgram(unittest.TestCase):
class FooBar(unittest.TestCase):
def testPass(self):
assert True
pass
def testFail(self):
assert False
raise AssertionError
class FooBarLoader(unittest.TestLoader):
"""Test loader that returns a suite containing FooBar."""
@@ -104,30 +105,39 @@ class Test_TestProgram(unittest.TestCase):
program.testNames)
def test_NonExit(self):
stream = BufferedWriter()
program = unittest.main(exit=False,
argv=["foobar"],
testRunner=unittest.TextTestRunner(stream=io.StringIO()),
testRunner=unittest.TextTestRunner(stream=stream),
testLoader=self.FooBarLoader())
self.assertTrue(hasattr(program, 'result'))
self.assertIn('\nFAIL: testFail ', stream.getvalue())
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
def test_Exit(self):
stream = BufferedWriter()
self.assertRaises(
SystemExit,
unittest.main,
argv=["foobar"],
testRunner=unittest.TextTestRunner(stream=io.StringIO()),
testRunner=unittest.TextTestRunner(stream=stream),
exit=True,
testLoader=self.FooBarLoader())
self.assertIn('\nFAIL: testFail ', stream.getvalue())
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
def test_ExitAsDefault(self):
stream = BufferedWriter()
self.assertRaises(
SystemExit,
unittest.main,
argv=["foobar"],
testRunner=unittest.TextTestRunner(stream=io.StringIO()),
testRunner=unittest.TextTestRunner(stream=stream),
testLoader=self.FooBarLoader())
self.assertIn('\nFAIL: testFail ', stream.getvalue())
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
class InitialisableProgram(unittest.TestProgram):
@@ -188,8 +198,6 @@ class TestCommandLineArgs(unittest.TestCase):
program = self.program
for arg, attr in (('buffer', 'buffer'), ('failfast', 'failfast'),
('catch', 'catchbreak')):
if attr == 'catch' and not hasInstallHandler:
continue
setattr(program, attr, None)
program.parseArgs([None])
+504 -8
View File
@@ -2,10 +2,11 @@ import io
import sys
import textwrap
from test.support import warnings_helper
from test.support import warnings_helper, captured_stdout, captured_stderr
import traceback
import unittest
from unittest.util import strclass
class MockTraceback(object):
@@ -22,6 +23,32 @@ def restore_traceback():
unittest.result.traceback = traceback
def bad_cleanup1():
print('do cleanup1')
raise TypeError('bad cleanup1')
def bad_cleanup2():
print('do cleanup2')
raise ValueError('bad cleanup2')
class BufferedWriter:
def __init__(self):
self.result = ''
self.buffer = ''
def write(self, arg):
self.buffer += arg
def flush(self):
self.result += self.buffer
self.buffer = ''
def getvalue(self):
return self.result
class Test_TestResult(unittest.TestCase):
# Note: there are not separate tests for TestResult.wasSuccessful(),
# TestResult.errors, TestResult.failures, TestResult.testsRun or
@@ -193,6 +220,61 @@ class Test_TestResult(unittest.TestCase):
self.assertIs(test_case, test)
self.assertIsInstance(formatted_exc, str)
def test_addFailure_filter_traceback_frames(self):
class Foo(unittest.TestCase):
def test_1(self):
pass
test = Foo('test_1')
def get_exc_info():
try:
test.fail("foo")
except:
return sys.exc_info()
exc_info_tuple = get_exc_info()
full_exc = traceback.format_exception(*exc_info_tuple)
result = unittest.TestResult()
result.startTest(test)
result.addFailure(test, exc_info_tuple)
result.stopTest(test)
formatted_exc = result.failures[0][1]
dropped = [l for l in full_exc if l not in formatted_exc]
self.assertEqual(len(dropped), 1)
self.assertIn("raise self.failureException(msg)", dropped[0])
def test_addFailure_filter_traceback_frames_context(self):
class Foo(unittest.TestCase):
def test_1(self):
pass
test = Foo('test_1')
def get_exc_info():
try:
try:
test.fail("foo")
except:
raise ValueError(42)
except:
return sys.exc_info()
exc_info_tuple = get_exc_info()
full_exc = traceback.format_exception(*exc_info_tuple)
result = unittest.TestResult()
result.startTest(test)
result.addFailure(test, exc_info_tuple)
result.stopTest(test)
formatted_exc = result.failures[0][1]
dropped = [l for l in full_exc if l not in formatted_exc]
self.assertEqual(len(dropped), 1)
self.assertIn("raise self.failureException(msg)", dropped[0])
# "addError(test, err)"
# ...
# "Called when the test case test raises an unexpected exception err
@@ -433,10 +515,13 @@ class Test_TestResult(unittest.TestCase):
self.assertTrue(result.shouldStop)
def testFailFastSetByRunner(self):
runner = unittest.TextTestRunner(stream=io.StringIO(), failfast=True)
stream = BufferedWriter()
runner = unittest.TextTestRunner(stream=stream, failfast=True)
def test(result):
self.assertTrue(result.failfast)
result = runner.run(test)
stream.flush()
self.assertTrue(stream.getvalue().endswith('\n\nOK\n'))
classDict = dict(unittest.TestResult.__dict__)
@@ -458,8 +543,8 @@ OldResult = type('OldResult', (object,), classDict)
class Test_OldTestResult(unittest.TestCase):
def assertOldResultWarning(self, test, failures):
with warnings_helper.check_warnings(("TestResult has no add.+ method,",
RuntimeWarning)):
with warnings_helper.check_warnings(
("TestResult has no add.+ method,", RuntimeWarning)):
result = OldResult()
test.run(result)
self.assertEqual(len(result.failures), failures)
@@ -633,36 +718,320 @@ class TestOutputBuffering(unittest.TestCase):
self.assertEqual(result._original_stderr.getvalue(), expectedErrMessage)
self.assertMultiLineEqual(message, expectedFullMessage)
def testBufferSetUp(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
def setUp(self):
print('set up')
1/0
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\nset up\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 1)
description = f'test_foo ({strclass(Foo)})'
test_case, formatted_exc = result.errors[0]
self.assertEqual(str(test_case), description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferTearDown(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
def tearDown(self):
print('tear down')
1/0
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\ntear down\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 1)
description = f'test_foo ({strclass(Foo)})'
test_case, formatted_exc = result.errors[0]
self.assertEqual(str(test_case), description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferDoCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
def setUp(self):
print('set up')
self.addCleanup(bad_cleanup1)
self.addCleanup(bad_cleanup2)
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\nset up\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 2)
description = f'test_foo ({strclass(Foo)})'
test_case, formatted_exc = result.errors[0]
self.assertEqual(str(test_case), description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
test_case, formatted_exc = result.errors[1]
self.assertEqual(str(test_case), description)
self.assertIn('TypeError: bad cleanup1', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferSetUp_DoCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
def setUp(self):
print('set up')
self.addCleanup(bad_cleanup1)
self.addCleanup(bad_cleanup2)
1/0
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\nset up\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 3)
description = f'test_foo ({strclass(Foo)})'
test_case, formatted_exc = result.errors[0]
self.assertEqual(str(test_case), description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
test_case, formatted_exc = result.errors[1]
self.assertEqual(str(test_case), description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
test_case, formatted_exc = result.errors[2]
self.assertEqual(str(test_case), description)
self.assertIn('TypeError: bad cleanup1', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferTearDown_DoCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
def setUp(self):
print('set up')
self.addCleanup(bad_cleanup1)
self.addCleanup(bad_cleanup2)
def tearDown(self):
print('tear down')
1/0
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\nset up\ntear down\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 3)
description = f'test_foo ({strclass(Foo)})'
test_case, formatted_exc = result.errors[0]
self.assertEqual(str(test_case), description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
test_case, formatted_exc = result.errors[1]
self.assertEqual(str(test_case), description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
test_case, formatted_exc = result.errors[2]
self.assertEqual(str(test_case), description)
self.assertIn('TypeError: bad cleanup1', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferSetupClass(self):
result = unittest.TestResult()
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
@classmethod
def setUpClass(cls):
print('set up class')
1/0
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\nset up class\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 1)
description = f'setUpClass ({strclass(Foo)})'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferTearDownClass(self):
result = unittest.TestResult()
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
@classmethod
def tearDownClass(cls):
print('tear down class')
1/0
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\ntear down class\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 1)
description = f'tearDownClass ({strclass(Foo)})'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferDoClassCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
@classmethod
def setUpClass(cls):
print('set up class')
cls.addClassCleanup(bad_cleanup1)
cls.addClassCleanup(bad_cleanup2)
@classmethod
def tearDownClass(cls):
print('tear down class')
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\ntear down class\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 2)
description = f'tearDownClass ({strclass(Foo)})'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
test_case, formatted_exc = result.errors[1]
self.assertEqual(test_case.description, description)
self.assertIn('TypeError: bad cleanup1', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferSetupClass_DoClassCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
@classmethod
def setUpClass(cls):
print('set up class')
cls.addClassCleanup(bad_cleanup1)
cls.addClassCleanup(bad_cleanup2)
1/0
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\nset up class\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 3)
description = f'setUpClass ({strclass(Foo)})'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn('\nStdout:\nset up class\n', formatted_exc)
test_case, formatted_exc = result.errors[1]
self.assertEqual(test_case.description, description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
test_case, formatted_exc = result.errors[2]
self.assertEqual(test_case.description, description)
self.assertIn('TypeError: bad cleanup1', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferTearDownClass_DoClassCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
@classmethod
def setUpClass(cls):
print('set up class')
cls.addClassCleanup(bad_cleanup1)
cls.addClassCleanup(bad_cleanup2)
@classmethod
def tearDownClass(cls):
print('tear down class')
1/0
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\ntear down class\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 3)
description = f'tearDownClass ({strclass(Foo)})'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn('\nStdout:\ntear down class\n', formatted_exc)
test_case, formatted_exc = result.errors[1]
self.assertEqual(test_case.description, description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
test_case, formatted_exc = result.errors[2]
self.assertEqual(test_case.description, description)
self.assertIn('TypeError: bad cleanup1', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferSetUpModule(self):
result = unittest.TestResult()
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
@@ -671,6 +1040,7 @@ class TestOutputBuffering(unittest.TestCase):
class Module(object):
@staticmethod
def setUpModule():
print('set up module')
1/0
Foo.__module__ = 'Module'
@@ -678,10 +1048,18 @@ class TestOutputBuffering(unittest.TestCase):
self.addCleanup(sys.modules.pop, 'Module')
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\nset up module\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 1)
description = 'setUpModule (Module)'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferTearDownModule(self):
result = unittest.TestResult()
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
@@ -690,6 +1068,7 @@ class TestOutputBuffering(unittest.TestCase):
class Module(object):
@staticmethod
def tearDownModule():
print('tear down module')
1/0
Foo.__module__ = 'Module'
@@ -697,7 +1076,124 @@ class TestOutputBuffering(unittest.TestCase):
self.addCleanup(sys.modules.pop, 'Module')
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\ntear down module\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 1)
description = 'tearDownModule (Module)'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferDoModuleCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
def test_foo(self):
pass
class Module(object):
@staticmethod
def setUpModule():
print('set up module')
unittest.addModuleCleanup(bad_cleanup1)
unittest.addModuleCleanup(bad_cleanup2)
Foo.__module__ = 'Module'
sys.modules['Module'] = Module
self.addCleanup(sys.modules.pop, 'Module')
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 1)
description = 'tearDownModule (Module)'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferSetUpModule_DoModuleCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
def test_foo(self):
pass
class Module(object):
@staticmethod
def setUpModule():
print('set up module')
unittest.addModuleCleanup(bad_cleanup1)
unittest.addModuleCleanup(bad_cleanup2)
1/0
Foo.__module__ = 'Module'
sys.modules['Module'] = Module
self.addCleanup(sys.modules.pop, 'Module')
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\nset up module\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 2)
description = 'setUpModule (Module)'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn('\nStdout:\nset up module\n', formatted_exc)
test_case, formatted_exc = result.errors[1]
self.assertIn(expected_out, formatted_exc)
self.assertEqual(test_case.description, description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
def testBufferTearDownModule_DoModuleCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
result.buffer = True
class Foo(unittest.TestCase):
def test_foo(self):
pass
class Module(object):
@staticmethod
def setUpModule():
print('set up module')
unittest.addModuleCleanup(bad_cleanup1)
unittest.addModuleCleanup(bad_cleanup2)
@staticmethod
def tearDownModule():
print('tear down module')
1/0
Foo.__module__ = 'Module'
sys.modules['Module'] = Module
self.addCleanup(sys.modules.pop, 'Module')
suite = unittest.TestSuite([Foo('test_foo')])
suite(result)
expected_out = '\nStdout:\ntear down module\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 2)
description = 'tearDownModule (Module)'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn('\nStdout:\ntear down module\n', formatted_exc)
test_case, formatted_exc = result.errors[1]
self.assertEqual(test_case.description, description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)
if __name__ == '__main__':
+865 -5
View File
@@ -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,834 @@ 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_run_class_cleanUp_without_tearDownClass(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
@property
def tearDownClass(cls):
raise AttributeError
runTests(TestableTest)
self.assertEqual(ordering, ['setUpClass', 'cleanup_good'])
ordering = []
blowUp = False
runTests(TestableTest)
self.assertEqual(ordering,
['setUpClass', 'test', 'cleanup_good'])
def test_debug_executes_classCleanUp(self):
ordering = []
blowUp = False
class TestableTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
ordering.append('setUpClass')
cls.addClassCleanup(cleanup, ordering, blowUp=blowUp)
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'])
ordering = []
blowUp = True
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
with self.assertRaises(Exception) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'CleanUpExc')
self.assertEqual(ordering,
['setUpClass', 'test', 'tearDownClass', 'cleanup_exc'])
def test_debug_executes_classCleanUp_when_teardown_exception(self):
ordering = []
blowUp = False
class TestableTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
ordering.append('setUpClass')
cls.addClassCleanup(cleanup, ordering, blowUp=blowUp)
def testNothing(self):
ordering.append('test')
@classmethod
def tearDownClass(cls):
raise Exception('TearDownClassExc')
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
with self.assertRaises(Exception) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'TearDownClassExc')
self.assertEqual(ordering, ['setUpClass', 'test'])
self.assertTrue(TestableTest._class_cleanups)
TestableTest._class_cleanups.clear()
ordering = []
blowUp = True
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
with self.assertRaises(Exception) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'TearDownClassExc')
self.assertEqual(ordering, ['setUpClass', 'test'])
self.assertTrue(TestableTest._class_cleanups)
TestableTest._class_cleanups.clear()
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.assertEqual(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'])
def test_with_errors_in_tearDownClass(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')
raise Exception('TearDownExc')
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
'Exception: TearDownExc')
self.assertEqual(ordering,
['setUpClass', 'test', 'tearDownClass', 'cleanup_good'])
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_addModuleCleanup_arg_errors(self):
cleanups = []
def cleanup(*args, **kwargs):
cleanups.append((args, kwargs))
class Module(object):
unittest.addModuleCleanup(cleanup, 1, 2, function='hello')
with self.assertRaises(TypeError):
unittest.addModuleCleanup(function=cleanup, arg='hello')
with self.assertRaises(TypeError):
unittest.addModuleCleanup()
unittest.case.doModuleCleanups()
self.assertEqual(cleanups,
[((1, 2), {'function': 'hello'})])
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_run_module_cleanUp_without_teardown(self):
ordering = []
class Module(object):
@staticmethod
def setUpModule():
ordering.append('setUpModule')
unittest.addModuleCleanup(cleanup, ordering)
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
runTests(TestableTest)
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test',
'tearDownClass', 'cleanup_good'])
self.assertEqual(unittest.case._module_cleanups, [])
def test_run_module_cleanUp_when_teardown_exception(self):
ordering = []
class Module(object):
@staticmethod
def setUpModule():
ordering.append('setUpModule')
unittest.addModuleCleanup(cleanup, ordering)
@staticmethod
def tearDownModule():
raise Exception('CleanUpExc')
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(result.errors[0][1].splitlines()[-1],
'Exception: CleanUpExc')
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test',
'tearDownClass', 'cleanup_good'])
self.assertEqual(unittest.case._module_cleanups, [])
def test_debug_module_executes_cleanUp(self):
ordering = []
blowUp = False
class Module(object):
@staticmethod
def setUpModule():
ordering.append('setUpModule')
unittest.addModuleCleanup(cleanup, ordering, blowUp=blowUp)
@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, [])
ordering = []
blowUp = True
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
with self.assertRaises(Exception) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'CleanUpExc')
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test',
'tearDownClass', 'tearDownModule', 'cleanup_exc'])
self.assertEqual(unittest.case._module_cleanups, [])
def test_debug_module_cleanUp_when_teardown_exception(self):
ordering = []
blowUp = False
class Module(object):
@staticmethod
def setUpModule():
ordering.append('setUpModule')
unittest.addModuleCleanup(cleanup, ordering, blowUp=blowUp)
@staticmethod
def tearDownModule():
raise Exception('TearDownModuleExc')
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)
with self.assertRaises(Exception) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'TearDownModuleExc')
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test',
'tearDownClass'])
self.assertTrue(unittest.case._module_cleanups)
unittest.case._module_cleanups.clear()
ordering = []
blowUp = True
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
with self.assertRaises(Exception) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'TearDownModuleExc')
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test',
'tearDownClass'])
self.assertTrue(unittest.case._module_cleanups)
unittest.case._module_cleanups.clear()
def test_addClassCleanup_arg_errors(self):
cleanups = []
def cleanup(*args, **kwargs):
cleanups.append((args, kwargs))
class TestableTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.addClassCleanup(cleanup, 1, 2, function=3, cls=4)
with self.assertRaises(TypeError):
cls.addClassCleanup(function=cleanup, arg='hello')
def testNothing(self):
pass
with self.assertRaises(TypeError):
TestableTest.addClassCleanup()
with self.assertRaises(TypeError):
unittest.TestCase.addCleanup(cls=TestableTest(), function=cleanup)
runTests(TestableTest)
self.assertEqual(cleanups,
[((1, 2), {'function': 3, 'cls': 4})])
def test_addCleanup_arg_errors(self):
cleanups = []
def cleanup(*args, **kwargs):
cleanups.append((args, kwargs))
class TestableTest(unittest.TestCase):
def setUp(self2):
self2.addCleanup(cleanup, 1, 2, function=3, self=4)
with self.assertRaises(TypeError):
self2.addCleanup(function=cleanup, arg='hello')
def testNothing(self):
pass
with self.assertRaises(TypeError):
TestableTest().addCleanup()
with self.assertRaises(TypeError):
unittest.TestCase.addCleanup(self=TestableTest(), function=cleanup)
runTests(TestableTest)
self.assertEqual(cleanups,
[((1, 2), {'function': 3, 'self': 4})])
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: ModuleExc')
self.assertEqual(result.errors[1][1].splitlines()[-1],
'Exception: CleanUpExc')
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."""
@@ -276,7 +1137,6 @@ class Test_TextTestRunner(unittest.TestCase):
expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY)
self.assertEqual(runner._makeResult(), expectedresult)
def test_warnings(self):
"""
Check that warnings argument of TextTestRunner correctly affects the
+285 -15
View File
@@ -7,30 +7,50 @@ class Test_TestSkipping(unittest.TestCase):
def test_skipping(self):
class Foo(unittest.TestCase):
def defaultTestResult(self):
return LoggingResult(events)
def test_skip_me(self):
self.skipTest("skip")
events = []
result = LoggingResult(events)
test = Foo("test_skip_me")
test.run(result)
self.assertIs(test.run(result), result)
self.assertEqual(events, ['startTest', 'addSkip', 'stopTest'])
self.assertEqual(result.skipped, [(test, "skip")])
events = []
result = test.run()
self.assertEqual(events, ['startTestRun', 'startTest', 'addSkip',
'stopTest', 'stopTestRun'])
self.assertEqual(result.skipped, [(test, "skip")])
self.assertEqual(result.testsRun, 1)
# Try letting setUp skip the test now.
class Foo(unittest.TestCase):
def defaultTestResult(self):
return LoggingResult(events)
def setUp(self):
self.skipTest("testing")
def test_nothing(self): pass
events = []
result = LoggingResult(events)
test = Foo("test_nothing")
test.run(result)
self.assertIs(test.run(result), result)
self.assertEqual(events, ['startTest', 'addSkip', 'stopTest'])
self.assertEqual(result.skipped, [(test, "testing")])
self.assertEqual(result.testsRun, 1)
events = []
result = test.run()
self.assertEqual(events, ['startTestRun', 'startTest', 'addSkip',
'stopTest', 'stopTestRun'])
self.assertEqual(result.skipped, [(test, "testing")])
self.assertEqual(result.testsRun, 1)
def test_skipping_subtests(self):
class Foo(unittest.TestCase):
def defaultTestResult(self):
return LoggingResult(events)
def test_skip_me(self):
with self.subTest(a=1):
with self.subTest(b=2):
@@ -40,7 +60,7 @@ class Test_TestSkipping(unittest.TestCase):
events = []
result = LoggingResult(events)
test = Foo("test_skip_me")
test.run(result)
self.assertIs(test.run(result), result)
self.assertEqual(events, ['startTest', 'addSkip', 'addSkip',
'addSkip', 'stopTest'])
self.assertEqual(len(result.skipped), 3)
@@ -54,11 +74,22 @@ class Test_TestSkipping(unittest.TestCase):
self.assertIsNot(subtest, test)
self.assertEqual(result.skipped[2], (test, "skip 3"))
events = []
result = test.run()
self.assertEqual(events,
['startTestRun', 'startTest', 'addSkip', 'addSkip',
'addSkip', 'stopTest', 'stopTestRun'])
self.assertEqual([msg for subtest, msg in result.skipped],
['skip 1', 'skip 2', 'skip 3'])
def test_skipping_decorators(self):
op_table = ((unittest.skipUnless, False, True),
(unittest.skipIf, True, False))
for deco, do_skip, dont_skip in op_table:
class Foo(unittest.TestCase):
def defaultTestResult(self):
return LoggingResult(events)
@deco(do_skip, "testing")
def test_skip(self): pass
@@ -66,10 +97,11 @@ class Test_TestSkipping(unittest.TestCase):
def test_dont_skip(self): pass
test_do_skip = Foo("test_skip")
test_dont_skip = Foo("test_dont_skip")
suite = unittest.TestSuite([test_do_skip, test_dont_skip])
events = []
result = LoggingResult(events)
suite.run(result)
self.assertIs(suite.run(result), result)
self.assertEqual(len(result.skipped), 1)
expected = ['startTest', 'addSkip', 'stopTest',
'startTest', 'addSuccess', 'stopTest']
@@ -78,16 +110,39 @@ class Test_TestSkipping(unittest.TestCase):
self.assertEqual(result.skipped, [(test_do_skip, "testing")])
self.assertTrue(result.wasSuccessful())
events = []
result = test_do_skip.run()
self.assertEqual(events, ['startTestRun', 'startTest', 'addSkip',
'stopTest', 'stopTestRun'])
self.assertEqual(result.skipped, [(test_do_skip, "testing")])
events = []
result = test_dont_skip.run()
self.assertEqual(events, ['startTestRun', 'startTest', 'addSuccess',
'stopTest', 'stopTestRun'])
self.assertEqual(result.skipped, [])
def test_skip_class(self):
@unittest.skip("testing")
class Foo(unittest.TestCase):
def defaultTestResult(self):
return LoggingResult(events)
def test_1(self):
record.append(1)
events = []
record = []
result = unittest.TestResult()
result = LoggingResult(events)
test = Foo("test_1")
suite = unittest.TestSuite([test])
suite.run(result)
self.assertIs(suite.run(result), result)
self.assertEqual(events, ['startTest', 'addSkip', 'stopTest'])
self.assertEqual(result.skipped, [(test, "testing")])
self.assertEqual(record, [])
events = []
result = test.run()
self.assertEqual(events, ['startTestRun', 'startTest', 'addSkip',
'stopTest', 'stopTestRun'])
self.assertEqual(result.skipped, [(test, "testing")])
self.assertEqual(record, [])
@@ -102,10 +157,62 @@ class Test_TestSkipping(unittest.TestCase):
result = unittest.TestResult()
test = Foo("test_1")
suite = unittest.TestSuite([test])
suite.run(result)
self.assertIs(suite.run(result), result)
self.assertEqual(result.skipped, [(test, "testing")])
self.assertEqual(record, [])
def test_skip_in_setup(self):
class Foo(unittest.TestCase):
def setUp(self):
self.skipTest("skip")
def test_skip_me(self):
self.fail("shouldn't come here")
events = []
result = LoggingResult(events)
test = Foo("test_skip_me")
self.assertIs(test.run(result), result)
self.assertEqual(events, ['startTest', 'addSkip', 'stopTest'])
self.assertEqual(result.skipped, [(test, "skip")])
def test_skip_in_cleanup(self):
class Foo(unittest.TestCase):
def test_skip_me(self):
pass
def tearDown(self):
self.skipTest("skip")
events = []
result = LoggingResult(events)
test = Foo("test_skip_me")
self.assertIs(test.run(result), result)
self.assertEqual(events, ['startTest', 'addSkip', 'stopTest'])
self.assertEqual(result.skipped, [(test, "skip")])
def test_failure_and_skip_in_cleanup(self):
class Foo(unittest.TestCase):
def test_skip_me(self):
self.fail("fail")
def tearDown(self):
self.skipTest("skip")
events = []
result = LoggingResult(events)
test = Foo("test_skip_me")
self.assertIs(test.run(result), result)
self.assertEqual(events, ['startTest', 'addSkip', 'addFailure', 'stopTest'])
self.assertEqual(result.skipped, [(test, "skip")])
def test_skipping_and_fail_in_cleanup(self):
class Foo(unittest.TestCase):
def test_skip_me(self):
self.skipTest("skip")
def tearDown(self):
self.fail("fail")
events = []
result = LoggingResult(events)
test = Foo("test_skip_me")
self.assertIs(test.run(result), result)
self.assertEqual(events, ['startTest', 'addSkip', 'addFailure', 'stopTest'])
self.assertEqual(result.skipped, [(test, "skip")])
def test_expected_failure(self):
class Foo(unittest.TestCase):
@unittest.expectedFailure
@@ -114,10 +221,12 @@ class Test_TestSkipping(unittest.TestCase):
events = []
result = LoggingResult(events)
test = Foo("test_die")
test.run(result)
self.assertIs(test.run(result), result)
self.assertEqual(events,
['startTest', 'addExpectedFailure', 'stopTest'])
self.assertFalse(result.failures)
self.assertEqual(result.expectedFailures[0][0], test)
self.assertFalse(result.unexpectedSuccesses)
self.assertTrue(result.wasSuccessful())
def test_expected_failure_with_wrapped_class(self):
@@ -129,10 +238,12 @@ class Test_TestSkipping(unittest.TestCase):
events = []
result = LoggingResult(events)
test = Foo("test_1")
test.run(result)
self.assertIs(test.run(result), result)
self.assertEqual(events,
['startTest', 'addExpectedFailure', 'stopTest'])
self.assertFalse(result.failures)
self.assertEqual(result.expectedFailures[0][0], test)
self.assertFalse(result.unexpectedSuccesses)
self.assertTrue(result.wasSuccessful())
def test_expected_failure_with_wrapped_subclass(self):
@@ -147,10 +258,12 @@ class Test_TestSkipping(unittest.TestCase):
events = []
result = LoggingResult(events)
test = Bar("test_1")
test.run(result)
self.assertIs(test.run(result), result)
self.assertEqual(events,
['startTest', 'addExpectedFailure', 'stopTest'])
self.assertFalse(result.failures)
self.assertEqual(result.expectedFailures[0][0], test)
self.assertFalse(result.unexpectedSuccesses)
self.assertTrue(result.wasSuccessful())
def test_expected_failure_subtests(self):
@@ -170,12 +283,52 @@ class Test_TestSkipping(unittest.TestCase):
events = []
result = LoggingResult(events)
test = Foo("test_die")
test.run(result)
self.assertIs(test.run(result), result)
self.assertEqual(events,
['startTest', 'addSubTestSuccess',
'addExpectedFailure', 'stopTest'])
self.assertFalse(result.failures)
self.assertEqual(len(result.expectedFailures), 1)
self.assertIs(result.expectedFailures[0][0], test)
self.assertFalse(result.unexpectedSuccesses)
self.assertTrue(result.wasSuccessful())
def test_expected_failure_and_fail_in_cleanup(self):
class Foo(unittest.TestCase):
@unittest.expectedFailure
def test_die(self):
self.fail("help me!")
def tearDown(self):
self.fail("bad tearDown")
events = []
result = LoggingResult(events)
test = Foo("test_die")
self.assertIs(test.run(result), result)
self.assertEqual(events,
['startTest', 'addFailure', 'stopTest'])
self.assertEqual(len(result.failures), 1)
self.assertIn('AssertionError: bad tearDown', result.failures[0][1])
self.assertFalse(result.expectedFailures)
self.assertFalse(result.unexpectedSuccesses)
self.assertFalse(result.wasSuccessful())
def test_expected_failure_and_skip_in_cleanup(self):
class Foo(unittest.TestCase):
@unittest.expectedFailure
def test_die(self):
self.fail("help me!")
def tearDown(self):
self.skipTest("skip")
events = []
result = LoggingResult(events)
test = Foo("test_die")
self.assertIs(test.run(result), result)
self.assertEqual(events,
['startTest', 'addSkip', 'stopTest'])
self.assertFalse(result.failures)
self.assertFalse(result.expectedFailures)
self.assertFalse(result.unexpectedSuccesses)
self.assertEqual(result.skipped, [(test, "skip")])
self.assertTrue(result.wasSuccessful())
def test_unexpected_success(self):
@@ -186,10 +339,11 @@ class Test_TestSkipping(unittest.TestCase):
events = []
result = LoggingResult(events)
test = Foo("test_die")
test.run(result)
self.assertIs(test.run(result), result)
self.assertEqual(events,
['startTest', 'addUnexpectedSuccess', 'stopTest'])
self.assertFalse(result.failures)
self.assertFalse(result.expectedFailures)
self.assertEqual(result.unexpectedSuccesses, [test])
self.assertFalse(result.wasSuccessful())
@@ -208,15 +362,54 @@ class Test_TestSkipping(unittest.TestCase):
events = []
result = LoggingResult(events)
test = Foo("test_die")
test.run(result)
self.assertIs(test.run(result), result)
self.assertEqual(events,
['startTest',
'addSubTestSuccess', 'addSubTestSuccess',
'addUnexpectedSuccess', 'stopTest'])
self.assertFalse(result.failures)
self.assertFalse(result.expectedFailures)
self.assertEqual(result.unexpectedSuccesses, [test])
self.assertFalse(result.wasSuccessful())
def test_unexpected_success_and_fail_in_cleanup(self):
class Foo(unittest.TestCase):
@unittest.expectedFailure
def test_die(self):
pass
def tearDown(self):
self.fail("bad tearDown")
events = []
result = LoggingResult(events)
test = Foo("test_die")
self.assertIs(test.run(result), result)
self.assertEqual(events,
['startTest', 'addFailure', 'stopTest'])
self.assertEqual(len(result.failures), 1)
self.assertIn('AssertionError: bad tearDown', result.failures[0][1])
self.assertFalse(result.expectedFailures)
self.assertFalse(result.unexpectedSuccesses)
self.assertFalse(result.wasSuccessful())
def test_unexpected_success_and_skip_in_cleanup(self):
class Foo(unittest.TestCase):
@unittest.expectedFailure
def test_die(self):
pass
def tearDown(self):
self.skipTest("skip")
events = []
result = LoggingResult(events)
test = Foo("test_die")
self.assertIs(test.run(result), result)
self.assertEqual(events,
['startTest', 'addSkip', 'stopTest'])
self.assertFalse(result.failures)
self.assertFalse(result.expectedFailures)
self.assertFalse(result.unexpectedSuccesses)
self.assertEqual(result.skipped, [(test, "skip")])
self.assertTrue(result.wasSuccessful())
def test_skip_doesnt_run_setup(self):
class Foo(unittest.TestCase):
wasSetUp = False
@@ -232,7 +425,7 @@ class Test_TestSkipping(unittest.TestCase):
result = unittest.TestResult()
test = Foo("test_1")
suite = unittest.TestSuite([test])
suite.run(result)
self.assertIs(suite.run(result), result)
self.assertEqual(result.skipped, [(test, "testing")])
self.assertFalse(Foo.wasSetUp)
self.assertFalse(Foo.wasTornDown)
@@ -252,9 +445,86 @@ class Test_TestSkipping(unittest.TestCase):
result = unittest.TestResult()
test = Foo("test_1")
suite = unittest.TestSuite([test])
suite.run(result)
self.assertIs(suite.run(result), result)
self.assertEqual(result.skipped, [(test, "testing")])
def test_skip_without_reason(self):
class Foo(unittest.TestCase):
@unittest.skip
def test_1(self):
pass
result = unittest.TestResult()
test = Foo("test_1")
suite = unittest.TestSuite([test])
self.assertIs(suite.run(result), result)
self.assertEqual(result.skipped, [(test, "")])
def test_debug_skipping(self):
class Foo(unittest.TestCase):
def setUp(self):
events.append("setUp")
def tearDown(self):
events.append("tearDown")
def test1(self):
self.skipTest('skipping exception')
events.append("test1")
@unittest.skip("skipping decorator")
def test2(self):
events.append("test2")
events = []
test = Foo("test1")
with self.assertRaises(unittest.SkipTest) as cm:
test.debug()
self.assertIn("skipping exception", str(cm.exception))
self.assertEqual(events, ["setUp"])
events = []
test = Foo("test2")
with self.assertRaises(unittest.SkipTest) as cm:
test.debug()
self.assertIn("skipping decorator", str(cm.exception))
self.assertEqual(events, [])
def test_debug_skipping_class(self):
@unittest.skip("testing")
class Foo(unittest.TestCase):
def setUp(self):
events.append("setUp")
def tearDown(self):
events.append("tearDown")
def test(self):
events.append("test")
events = []
test = Foo("test")
with self.assertRaises(unittest.SkipTest) as cm:
test.debug()
self.assertIn("testing", str(cm.exception))
self.assertEqual(events, [])
def test_debug_skipping_subtests(self):
class Foo(unittest.TestCase):
def setUp(self):
events.append("setUp")
def tearDown(self):
events.append("tearDown")
def test(self):
with self.subTest(a=1):
events.append('subtest')
self.skipTest("skip subtest")
events.append('end subtest')
events.append('end test')
events = []
result = LoggingResult(events)
test = Foo("test")
with self.assertRaises(unittest.SkipTest) as cm:
test.debug()
self.assertIn("skip subtest", str(cm.exception))
self.assertEqual(events, ['setUp', 'subtest'])
if __name__ == "__main__":
unittest.main()
+1 -1
View File
@@ -1,6 +1,6 @@
import unittest
# import gc
import gc
import sys
import weakref
from unittest.test.support import LoggingResult, TestEquality
+4 -9
View File
@@ -1,3 +1,6 @@
target = {'foo': 'FOO'}
def is_instance(obj, klass):
"""Version of is_instance that doesn't access __class__"""
return issubclass(type(obj), klass)
@@ -6,16 +9,8 @@ def is_instance(obj, klass):
class SomeClass(object):
class_attribute = None
def wibble(self):
pass
def wibble(self): pass
class X(object):
pass
def examine_warnings(func):
def wrapper():
with catch_warnings(record=True) as ws:
func(ws)
return wrapper
File diff suppressed because it is too large. Load diff
+2 -3
View File
@@ -98,8 +98,7 @@ class TestCallable(unittest.TestCase):
def test_patch_spec_callable_class(self):
class CallableX(X):
def __call__(self):
pass
def __call__(self): pass
class Sub(CallableX):
pass
@@ -128,7 +127,7 @@ class TestCallable(unittest.TestCase):
result.foo.assert_called_once_with(3, 2, 1)
def test_create_autopsec(self):
def test_create_autospec(self):
mock = create_autospec(X)
instance = mock()
self.assertRaises(TypeError, instance)
+255 -74
View File
@@ -1,21 +1,20 @@
import inspect
import time
import types
import unittest
from unittest.mock import (
call, _Call, create_autospec, MagicMock,
Mock, ANY, _CallList, patch, PropertyMock
Mock, ANY, _CallList, patch, PropertyMock, _callable
)
from datetime import datetime
from functools import partial
class SomeClass(object):
def one(self, a, b):
pass
def two(self):
pass
def three(self, a=None):
pass
def one(self, a, b): pass
def two(self): pass
def three(self, a=None): pass
@@ -46,12 +45,9 @@ class AnyTest(unittest.TestCase):
def test_any_mock_calls_comparison_order(self):
mock = Mock()
d = datetime.now()
class Foo(object):
def __eq__(self, other):
return False
def __ne__(self, other):
return True
def __eq__(self, other): pass
def __ne__(self, other): pass
for d in datetime.now(), Foo():
mock.reset_mock()
@@ -68,7 +64,28 @@ class AnyTest(unittest.TestCase):
self.assertEqual(expected, mock.mock_calls)
self.assertEqual(mock.mock_calls, expected)
def test_any_no_spec(self):
# This is a regression test for bpo-37555
class Foo:
def __eq__(self, other): pass
mock = Mock()
mock(Foo(), 1)
mock.assert_has_calls([call(ANY, 1)])
mock.assert_called_with(ANY, 1)
mock.assert_any_call(ANY, 1)
def test_any_and_spec_set(self):
# This is a regression test for bpo-37555
class Foo:
def __eq__(self, other): pass
mock = Mock(spec=Foo)
mock(Foo(), 1)
mock.assert_has_calls([call(ANY, 1)])
mock.assert_called_with(ANY, 1)
mock.assert_any_call(ANY, 1)
class CallTest(unittest.TestCase):
@@ -144,6 +161,8 @@ class CallTest(unittest.TestCase):
self.assertEqual(args, ('foo', (1, 2, 3)))
self.assertEqual(args, ('foo', (1, 2, 3), {}))
self.assertEqual(args, ((1, 2, 3), {}))
self.assertEqual(args.args, (1, 2, 3))
self.assertEqual(args.kwargs, {})
def test_named_call_with_args(self):
@@ -151,6 +170,8 @@ class CallTest(unittest.TestCase):
self.assertEqual(args, ('foo', (1, 2, 3)))
self.assertEqual(args, ('foo', (1, 2, 3), {}))
self.assertEqual(args.args, (1, 2, 3))
self.assertEqual(args.kwargs, {})
self.assertNotEqual(args, ((1, 2, 3),))
self.assertNotEqual(args, ((1, 2, 3), {}))
@@ -163,6 +184,8 @@ class CallTest(unittest.TestCase):
self.assertEqual(args, ('foo', dict(a=3, b=4)))
self.assertEqual(args, ('foo', (), dict(a=3, b=4)))
self.assertEqual(args, ((), dict(a=3, b=4)))
self.assertEqual(args.args, ())
self.assertEqual(args.kwargs, dict(a=3, b=4))
def test_named_call_with_kwargs(self):
@@ -170,6 +193,8 @@ class CallTest(unittest.TestCase):
self.assertEqual(args, ('foo', dict(a=3, b=4)))
self.assertEqual(args, ('foo', (), dict(a=3, b=4)))
self.assertEqual(args.args, ())
self.assertEqual(args.kwargs, dict(a=3, b=4))
self.assertNotEqual(args, (dict(a=3, b=4),))
self.assertNotEqual(args, ((), dict(a=3, b=4)))
@@ -177,6 +202,7 @@ class CallTest(unittest.TestCase):
def test_call_with_args_call_empty_name(self):
args = _Call(((1, 2, 3), {}))
self.assertEqual(args, call(1, 2, 3))
self.assertEqual(call(1, 2, 3), args)
self.assertIn(call(1, 2, 3), [args])
@@ -269,6 +295,22 @@ class CallTest(unittest.TestCase):
self.assertEqual(mock.mock_calls, last_call.call_list())
def test_extended_not_equal(self):
a = call(x=1).foo
b = call(x=2).foo
self.assertEqual(a, a)
self.assertEqual(b, b)
self.assertNotEqual(a, b)
def test_nested_calls_not_equal(self):
a = call(x=1).foo().bar
b = call(x=2).foo().bar
self.assertEqual(a, a)
self.assertEqual(b, b)
self.assertNotEqual(a, b)
def test_call_list(self):
mock = MagicMock()
mock(1)
@@ -313,6 +355,26 @@ class CallTest(unittest.TestCase):
self.assertEqual(_Call((('bar', 'barz'),),)[0], '')
self.assertEqual(_Call((('bar', 'barz'), {'hello': 'world'}),)[0], '')
def test_dunder_call(self):
m = MagicMock()
m().foo()['bar']()
self.assertEqual(
m.mock_calls,
[call(), call().foo(), call().foo().__getitem__('bar'), call().foo().__getitem__()()]
)
m = MagicMock()
m().foo()['bar'] = 1
self.assertEqual(
m.mock_calls,
[call(), call().foo(), call().foo().__setitem__('bar', 1)]
)
m = MagicMock()
iter(m().foo())
self.assertEqual(
m.mock_calls,
[call(), call().foo(), call().foo().__iter__()]
)
class SpecSignatureTest(unittest.TestCase):
@@ -351,8 +413,7 @@ class SpecSignatureTest(unittest.TestCase):
def test_create_autospec_return_value(self):
def f():
pass
def f(): pass
mock = create_autospec(f, return_value='foo')
self.assertEqual(mock(), 'foo')
@@ -372,8 +433,7 @@ class SpecSignatureTest(unittest.TestCase):
def test_mocking_unbound_methods(self):
class Foo(object):
def foo(self, foo):
pass
def foo(self, foo): pass
p = patch.object(Foo, 'foo')
mock_foo = p.start()
Foo().foo(1)
@@ -381,24 +441,6 @@ class SpecSignatureTest(unittest.TestCase):
mock_foo.assert_called_with(1)
def test_create_autospec_unbound_methods(self):
# see mock issue 128
# this is expected to fail until the issue is fixed
return
class Foo(object):
def foo(self):
pass
klass = create_autospec(Foo)
instance = klass()
self.assertRaises(TypeError, instance.foo, 1)
# Note: no type checking on the "self" parameter
klass.foo(1)
klass.foo.assert_called_with(1)
self.assertRaises(TypeError, klass.foo)
def test_create_autospec_keyword_arguments(self):
class Foo(object):
a = 3
@@ -407,8 +449,7 @@ class SpecSignatureTest(unittest.TestCase):
def test_create_autospec_keyword_only_arguments(self):
def foo(a, *, b=None):
pass
def foo(a, *, b=None): pass
m = create_autospec(foo)
m(1)
@@ -421,8 +462,7 @@ class SpecSignatureTest(unittest.TestCase):
def test_function_as_instance_attribute(self):
obj = SomeClass()
def f(a):
pass
def f(a): pass
obj.f = f
mock = create_autospec(obj)
@@ -458,13 +498,57 @@ class SpecSignatureTest(unittest.TestCase):
self._check_someclass_mock(mock)
def test_spec_has_descriptor_returning_function(self):
class CrazyDescriptor(object):
def __get__(self, obj, type_):
if obj is None:
return lambda x: None
class MyClass(object):
some_attr = CrazyDescriptor()
mock = create_autospec(MyClass)
mock.some_attr(1)
with self.assertRaises(TypeError):
mock.some_attr()
with self.assertRaises(TypeError):
mock.some_attr(1, 2)
def test_spec_has_function_not_in_bases(self):
class CrazyClass(object):
def __dir__(self):
return super(CrazyClass, self).__dir__()+['crazy']
def __getattr__(self, item):
if item == 'crazy':
return lambda x: x
raise AttributeError(item)
inst = CrazyClass()
with self.assertRaises(AttributeError):
inst.other
self.assertEqual(inst.crazy(42), 42)
mock = create_autospec(inst)
mock.crazy(42)
with self.assertRaises(TypeError):
mock.crazy()
with self.assertRaises(TypeError):
mock.crazy(1, 2)
def test_builtin_functions_types(self):
# we could replace builtin functions / methods with a function
# with *args / **kwargs signature. Using the builtin method type
# as a spec seems to work fairly well though.
class BuiltinSubclass(list):
def bar(self, arg):
pass
def bar(self, arg): pass
sorted = sorted
attr = {}
@@ -538,17 +622,13 @@ class SpecSignatureTest(unittest.TestCase):
def test_descriptors(self):
class Foo(object):
@classmethod
def f(cls, a, b):
pass
def f(cls, a, b): pass
@staticmethod
def g(a, b):
pass
def g(a, b): pass
class Bar(Foo):
pass
class Bar(Foo): pass
class Baz(SomeClass, Bar):
pass
class Baz(SomeClass, Bar): pass
for spec in (Foo, Foo(), Bar, Bar(), Baz, Baz()):
mock = create_autospec(spec)
@@ -561,8 +641,7 @@ class SpecSignatureTest(unittest.TestCase):
def test_recursive(self):
class A(object):
def a(self):
pass
def a(self): pass
foo = 'foo bar baz'
bar = foo
@@ -584,11 +663,9 @@ class SpecSignatureTest(unittest.TestCase):
def test_spec_inheritance_for_classes(self):
class Foo(object):
def a(self, x):
pass
def a(self, x): pass
class Bar(object):
def f(self, y):
pass
def f(self, y): pass
class_mock = create_autospec(Foo)
@@ -668,8 +745,7 @@ class SpecSignatureTest(unittest.TestCase):
def test_function(self):
def f(a, b):
pass
def f(a, b): pass
mock = create_autospec(f)
self.assertRaises(TypeError, mock)
@@ -699,9 +775,10 @@ class SpecSignatureTest(unittest.TestCase):
def existing(a, b):
return a + b
self.assertEqual(RaiserClass.existing(1, 2), 3)
s = create_autospec(RaiserClass)
self.assertRaises(TypeError, lambda x: s.existing(1, 2, 3))
s.existing(1, 2)
self.assertEqual(s.existing(1, 2), s.existing.return_value)
self.assertRaises(AttributeError, lambda: s.nonexisting)
# check we can fetch the raiser attribute and it has no spec
@@ -711,8 +788,7 @@ class SpecSignatureTest(unittest.TestCase):
def test_signature_class(self):
class Foo(object):
def __init__(self, a, b=3):
pass
def __init__(self, a, b=3): pass
mock = create_autospec(Foo)
@@ -738,10 +814,8 @@ class SpecSignatureTest(unittest.TestCase):
def test_signature_callable(self):
class Callable(object):
def __init__(self, x, y):
pass
def __call__(self, a):
pass
def __init__(self, x, y): pass
def __call__(self, a): pass
mock = create_autospec(Callable)
mock(1, 2)
@@ -797,8 +871,7 @@ class SpecSignatureTest(unittest.TestCase):
def test_autospec_functions_with_self_in_odd_place(self):
class Foo(object):
def f(a, self):
pass
def f(a, self): pass
a = create_autospec(Foo)
a.f(10)
@@ -815,12 +888,9 @@ class SpecSignatureTest(unittest.TestCase):
self.value = value
def __get__(self, obj, cls=None):
if obj is None:
return self
return self.value
return self
def __set__(self, obj, value):
pass
def __set__(self, obj, value): pass
class MyProperty(property):
pass
@@ -829,12 +899,10 @@ class SpecSignatureTest(unittest.TestCase):
__slots__ = ['slot']
@property
def prop(self):
return 3
def prop(self): pass
@MyProperty
def subprop(self):
return 4
def subprop(self): pass
desc = Descriptor(42)
@@ -871,6 +939,84 @@ class SpecSignatureTest(unittest.TestCase):
mocked.assert_called_once_with(4, 5, 6)
def test_autospec_getattr_partial_function(self):
# bpo-32153 : getattr returning partial functions without
# __name__ should not create AttributeError in create_autospec
class Foo:
def __getattr__(self, attribute):
return partial(lambda name: name, attribute)
proxy = Foo()
autospec = create_autospec(proxy)
self.assertFalse(hasattr(autospec, '__name__'))
def test_spec_inspect_signature(self):
def myfunc(x, y): pass
mock = create_autospec(myfunc)
mock(1, 2)
mock(x=1, y=2)
self.assertEqual(inspect.signature(mock), inspect.signature(myfunc))
self.assertEqual(mock.mock_calls, [call(1, 2), call(x=1, y=2)])
self.assertRaises(TypeError, mock, 1)
def test_spec_inspect_signature_annotations(self):
def foo(a: int, b: int=10, *, c:int) -> int:
return a + b + c
self.assertEqual(foo(1, 2 , c=3), 6)
mock = create_autospec(foo)
mock(1, 2, c=3)
mock(1, c=3)
self.assertEqual(inspect.signature(mock), inspect.signature(foo))
self.assertEqual(mock.mock_calls, [call(1, 2, c=3), call(1, c=3)])
self.assertRaises(TypeError, mock, 1)
self.assertRaises(TypeError, mock, 1, 2, 3, c=4)
def test_spec_function_no_name(self):
func = lambda: 'nope'
mock = create_autospec(func)
self.assertEqual(mock.__name__, 'funcopy')
def test_spec_function_assert_has_calls(self):
def f(a): pass
mock = create_autospec(f)
mock(1)
mock.assert_has_calls([call(1)])
with self.assertRaises(AssertionError):
mock.assert_has_calls([call(2)])
def test_spec_function_assert_any_call(self):
def f(a): pass
mock = create_autospec(f)
mock(1)
mock.assert_any_call(1)
with self.assertRaises(AssertionError):
mock.assert_any_call(2)
def test_spec_function_reset_mock(self):
def f(a): pass
rv = Mock()
mock = create_autospec(f, return_value=rv)
mock(1)(2)
self.assertEqual(mock.mock_calls, [call(1)])
self.assertEqual(rv.mock_calls, [call(2)])
mock.reset_mock()
self.assertEqual(mock.mock_calls, [])
self.assertEqual(rv.mock_calls, [])
class TestCallList(unittest.TestCase):
def test_args_list_contains_call_list(self):
@@ -942,5 +1088,40 @@ class TestCallList(unittest.TestCase):
self.assertNotIsInstance(returned, PropertyMock)
class TestCallablePredicate(unittest.TestCase):
def test_type(self):
for obj in [str, bytes, int, list, tuple, SomeClass]:
self.assertTrue(_callable(obj))
def test_call_magic_method(self):
class Callable:
def __call__(self): pass
instance = Callable()
self.assertTrue(_callable(instance))
def test_staticmethod(self):
class WithStaticMethod:
@staticmethod
def staticfunc(): pass
self.assertTrue(_callable(WithStaticMethod.staticfunc))
def test_non_callable_staticmethod(self):
class BadStaticMethod:
not_callable = staticmethod(None)
self.assertFalse(_callable(BadStaticMethod.not_callable))
def test_classmethod(self):
class WithClassMethod:
@classmethod
def classfunc(cls): pass
self.assertTrue(_callable(WithClassMethod.classfunc))
def test_non_callable_classmethod(self):
class BadClassMethod:
not_callable = classmethod(None)
self.assertFalse(_callable(BadClassMethod.not_callable))
if __name__ == '__main__':
unittest.main()
+48 -7
View File
@@ -1,6 +1,8 @@
import math
import unittest
import sys
from unittest.mock import Mock, MagicMock, _magics
import os
from asyncio import iscoroutinefunction
from unittest.mock import AsyncMock, Mock, MagicMock, _magics
@@ -268,6 +270,31 @@ class TestMockingMagicMethods(unittest.TestCase):
self.assertEqual(mock == mock, True)
self.assertEqual(mock != mock, False)
def test_asyncmock_defaults(self):
mock = AsyncMock()
self.assertEqual(int(mock), 1)
self.assertEqual(complex(mock), 1j)
self.assertEqual(float(mock), 1.0)
self.assertNotIn(object(), mock)
self.assertEqual(len(mock), 0)
self.assertEqual(list(mock), [])
self.assertEqual(hash(mock), object.__hash__(mock))
self.assertEqual(str(mock), object.__str__(mock))
self.assertTrue(bool(mock))
self.assertEqual(round(mock), mock.__round__())
self.assertEqual(math.trunc(mock), mock.__trunc__())
self.assertEqual(math.floor(mock), mock.__floor__())
self.assertEqual(math.ceil(mock), mock.__ceil__())
self.assertTrue(iscoroutinefunction(mock.__aexit__))
self.assertTrue(iscoroutinefunction(mock.__aenter__))
self.assertIsInstance(mock.__aenter__, AsyncMock)
self.assertIsInstance(mock.__aexit__, AsyncMock)
# in Python 3 oct and hex use __index__
# so these tests are for __index__ in py3k
self.assertEqual(oct(mock), '0o1')
self.assertEqual(hex(mock), '0x1')
# how to test __sizeof__ ?
def test_magicmock_defaults(self):
mock = MagicMock()
@@ -280,6 +307,14 @@ class TestMockingMagicMethods(unittest.TestCase):
self.assertEqual(hash(mock), object.__hash__(mock))
self.assertEqual(str(mock), object.__str__(mock))
self.assertTrue(bool(mock))
self.assertEqual(round(mock), mock.__round__())
self.assertEqual(math.trunc(mock), mock.__trunc__())
self.assertEqual(math.floor(mock), mock.__floor__())
self.assertEqual(math.ceil(mock), mock.__ceil__())
self.assertTrue(iscoroutinefunction(mock.__aexit__))
self.assertTrue(iscoroutinefunction(mock.__aenter__))
self.assertIsInstance(mock.__aenter__, AsyncMock)
self.assertIsInstance(mock.__aexit__, AsyncMock)
# in Python 3 oct and hex use __index__
# so these tests are for __index__ in py3k
@@ -288,10 +323,18 @@ class TestMockingMagicMethods(unittest.TestCase):
# how to test __sizeof__ ?
def test_magic_methods_fspath(self):
mock = MagicMock()
expected_path = mock.__fspath__()
mock.reset_mock()
self.assertEqual(os.fspath(mock), expected_path)
mock.__fspath__.assert_called_once()
def test_magic_methods_and_spec(self):
class Iterable(object):
def __iter__(self):
pass
def __iter__(self): pass
mock = Mock(spec=Iterable)
self.assertRaises(AttributeError, lambda: mock.__iter__)
@@ -315,8 +358,7 @@ class TestMockingMagicMethods(unittest.TestCase):
def test_magic_methods_and_spec_set(self):
class Iterable(object):
def __iter__(self):
pass
def __iter__(self): pass
mock = Mock(spec_set=Iterable)
self.assertRaises(AttributeError, lambda: mock.__iter__)
@@ -386,7 +428,6 @@ class TestMockingMagicMethods(unittest.TestCase):
self.assertEqual(dir(mock), ['foo'])
@unittest.skipIf('PyPy' in sys.version, "This fails differently on pypy")
def test_bound_methods(self):
m = Mock()
+748 -63
View File
File diff suppressed because it is too large. Load diff
+214 -114
View File
@@ -4,11 +4,13 @@
import os
import sys
from collections import OrderedDict
import unittest
from unittest.test.testmock import support
from unittest.test.testmock.support import SomeClass, is_instance
from test.test_importlib.util import uncache
from unittest.mock import (
NonCallableMock, CallableMixin, sentinel,
MagicMock, Mock, NonCallableMagicMock, patch, _patch,
@@ -42,23 +44,24 @@ something_else = sentinel.SomethingElse
class Foo(object):
def __init__(self, a):
pass
def f(self, a):
pass
def g(self):
pass
def __init__(self, a): pass
def f(self, a): pass
def g(self): pass
foo = 'bar'
@staticmethod
def static_method(): pass
@classmethod
def class_method(cls): pass
class Bar(object):
def a(self):
pass
def a(self): pass
foo_name = '%s.Foo' % __name__
def function(a, b=Foo):
pass
def function(a, b=Foo): pass
class Container(object):
@@ -103,6 +106,10 @@ class PatchTest(unittest.TestCase):
self.assertEqual(Something.attribute, sentinel.Original,
"patch not restored")
def test_patchobject_with_string_as_target(self):
msg = "'Something' must be the actual object to be patched, not a str"
with self.assertRaisesRegex(TypeError, msg):
patch.object('Something', 'do_something')
def test_patchobject_with_none(self):
class Something(object):
@@ -361,31 +368,19 @@ class PatchTest(unittest.TestCase):
def test_patch_wont_create_by_default(self):
try:
with self.assertRaises(AttributeError):
@patch('%s.frooble' % builtin_string, sentinel.Frooble)
def test():
self.assertEqual(frooble, sentinel.Frooble)
def test(): pass
test()
except AttributeError:
pass
else:
self.fail('Patching non existent attributes should fail')
self.assertRaises(NameError, lambda: frooble)
def test_patchobject_wont_create_by_default(self):
try:
with self.assertRaises(AttributeError):
@patch.object(SomeClass, 'ord', sentinel.Frooble)
def test():
self.fail('Patching non existent attributes should fail')
def test(): pass
test()
except AttributeError:
pass
else:
self.fail('Patching non existent attributes should fail')
self.assertFalse(hasattr(SomeClass, 'ord'))
@@ -475,6 +470,9 @@ class PatchTest(unittest.TestCase):
attribute = sentinel.Original
class Foo(object):
test_class_attr = 'whatever'
def test_method(other_self, mock_something):
self.assertEqual(PTModule.something, mock_something,
"unpatched")
@@ -626,6 +624,13 @@ class PatchTest(unittest.TestCase):
self.assertEqual(foo.values, original)
def test_patch_dict_as_context_manager(self):
foo = {'a': 'b'}
with patch.dict(foo, a='c') as patched:
self.assertEqual(patched, {'a': 'c'})
self.assertEqual(foo, {'a': 'b'})
def test_name_preserved(self):
foo = {}
@@ -633,8 +638,7 @@ class PatchTest(unittest.TestCase):
@patch('%s.SomeClass' % __name__, object(), autospec=True)
@patch.object(SomeClass, object())
@patch.dict(foo)
def some_name():
pass
def some_name(): pass
self.assertEqual(some_name.__name__, 'some_name')
@@ -645,12 +649,9 @@ class PatchTest(unittest.TestCase):
@patch.dict(foo, {'a': 'b'})
def test():
raise NameError('Konrad')
try:
with self.assertRaises(NameError):
test()
except NameError:
pass
else:
self.fail('NameError not raised by test')
self.assertEqual(foo, {})
@@ -663,47 +664,21 @@ class PatchTest(unittest.TestCase):
test()
def test_patch_descriptor(self):
# would be some effort to fix this - we could special case the
# builtin descriptors: classmethod, property, staticmethod
return
class Nothing(object):
foo = None
def test_patch_dict_decorator_resolution(self):
# bpo-35512: Ensure that patch with a string target resolves to
# the new dictionary during function call
original = support.target.copy()
class Something(object):
foo = {}
@patch.dict('unittest.test.testmock.support.target', {'bar': 'BAR'})
def test():
self.assertEqual(support.target, {'foo': 'BAZ', 'bar': 'BAR'})
@patch.object(Nothing, 'foo', 2)
@classmethod
def klass(cls):
self.assertIs(cls, Something)
@patch.object(Nothing, 'foo', 2)
@staticmethod
def static(arg):
return arg
@patch.dict(foo)
@classmethod
def klass_dict(cls):
self.assertIs(cls, Something)
@patch.dict(foo)
@staticmethod
def static_dict(arg):
return arg
# these will raise exceptions if patching descriptors is broken
self.assertEqual(Something.static('f00'), 'f00')
Something.klass()
self.assertEqual(Something.static_dict('f00'), 'f00')
Something.klass_dict()
something = Something()
self.assertEqual(something.static('f00'), 'f00')
something.klass()
self.assertEqual(something.static_dict('f00'), 'f00')
something.klass_dict()
try:
support.target = {'foo': 'BAZ'}
test()
self.assertEqual(support.target, {'foo': 'BAZ'})
finally:
support.target = original
def test_patch_spec_set(self):
@@ -754,10 +729,18 @@ class PatchTest(unittest.TestCase):
def test_stop_without_start(self):
# bpo-36366: calling stop without start will return None.
patcher = patch(foo_name, 'bar', 3)
self.assertIsNone(patcher.stop())
def test_stop_idempotent(self):
# bpo-36366: calling stop on an already stopped patch will return None.
patcher = patch(foo_name, 'bar', 3)
# calling stop without start used to produce a very obscure error
self.assertRaises(RuntimeError, patcher.stop)
patcher.start()
patcher.stop()
self.assertIsNone(patcher.stop())
def test_patchobject_start_stop(self):
@@ -787,6 +770,14 @@ class PatchTest(unittest.TestCase):
self.assertEqual(d, original)
def test_patch_dict_stop_without_start(self):
d = {'foo': 'bar'}
original = d.copy()
patcher = patch.dict(d, [('spam', 'eggs')], clear=True)
self.assertFalse(patcher.stop())
self.assertEqual(d, original)
def test_patch_dict_class_decorator(self):
this = self
d = {'spam': 'eggs'}
@@ -897,17 +888,13 @@ class PatchTest(unittest.TestCase):
def test_autospec(self):
class Boo(object):
def __init__(self, a):
pass
def f(self, a):
pass
def g(self):
pass
def __init__(self, a): pass
def f(self, a): pass
def g(self): pass
foo = 'bar'
class Bar(object):
def a(self):
pass
def a(self): pass
def _test(mock):
mock(1)
@@ -997,6 +984,18 @@ class PatchTest(unittest.TestCase):
self.assertEqual(result, 3)
def test_autospec_staticmethod(self):
with patch('%s.Foo.static_method' % __name__, autospec=True) as method:
Foo.static_method()
method.assert_called_once_with()
def test_autospec_classmethod(self):
with patch('%s.Foo.class_method' % __name__, autospec=True) as method:
Foo.class_method()
method.assert_called_once_with()
def test_autospec_with_new(self):
patcher = patch('%s.function' % __name__, new=3, autospec=True)
self.assertRaises(TypeError, patcher.start)
@@ -1266,7 +1265,6 @@ class PatchTest(unittest.TestCase):
def test_patch_multiple_create_mocks_different_order(self):
# bug revealed by Jython!
original_f = Foo.f
original_g = Foo.g
@@ -1443,20 +1441,17 @@ class PatchTest(unittest.TestCase):
@patch.object(Foo, 'g', 1)
@patch.object(Foo, 'missing', 1)
@patch.object(Foo, 'f', 1)
def thing1():
pass
def thing1(): pass
@patch.object(Foo, 'missing', 1)
@patch.object(Foo, 'g', 1)
@patch.object(Foo, 'f', 1)
def thing2():
pass
def thing2(): pass
@patch.object(Foo, 'g', 1)
@patch.object(Foo, 'f', 1)
@patch.object(Foo, 'missing', 1)
def thing3():
pass
def thing3(): pass
for func in thing1, thing2, thing3:
self.assertRaises(AttributeError, func)
@@ -1475,20 +1470,17 @@ class PatchTest(unittest.TestCase):
@patch.object(Foo, 'g', 1)
@patch.object(Foo, 'foo', new_callable=crasher)
@patch.object(Foo, 'f', 1)
def thing1():
pass
def thing1(): pass
@patch.object(Foo, 'foo', new_callable=crasher)
@patch.object(Foo, 'g', 1)
@patch.object(Foo, 'f', 1)
def thing2():
pass
def thing2(): pass
@patch.object(Foo, 'g', 1)
@patch.object(Foo, 'f', 1)
@patch.object(Foo, 'foo', new_callable=crasher)
def thing3():
pass
def thing3(): pass
for func in thing1, thing2, thing3:
self.assertRaises(NameError, func)
@@ -1514,8 +1506,7 @@ class PatchTest(unittest.TestCase):
patcher.additional_patchers = additionals
@patcher
def func():
pass
def func(): pass
self.assertRaises(AttributeError, func)
self.assertEqual(Foo.f, original_f)
@@ -1543,8 +1534,7 @@ class PatchTest(unittest.TestCase):
patcher.additional_patchers = additionals
@patcher
def func():
pass
def func(): pass
self.assertRaises(NameError, func)
self.assertEqual(Foo.f, original_f)
@@ -1660,22 +1650,21 @@ class PatchTest(unittest.TestCase):
def test_patch_imports_lazily(self):
sys.modules.pop('squizz', None)
p1 = patch('squizz.squozz')
self.assertRaises(ImportError, p1.start)
squizz = Mock()
squizz.squozz = 6
sys.modules['squizz'] = squizz
p1 = patch('squizz.squozz')
squizz.squozz = 3
p1.start()
p1.stop()
with uncache('squizz'):
squizz = Mock()
sys.modules['squizz'] = squizz
squizz.squozz = 6
p1 = patch('squizz.squozz')
squizz.squozz = 3
p1.start()
p1.stop()
self.assertEqual(squizz.squozz, 3)
def test_patch_propogrates_exc_on_exit(self):
def test_patch_propagates_exc_on_exit(self):
class holder:
exc_info = None, None, None
@@ -1696,12 +1685,17 @@ class PatchTest(unittest.TestCase):
def test(mock):
raise RuntimeError
self.assertRaises(RuntimeError, test)
with uncache('squizz'):
squizz = Mock()
sys.modules['squizz'] = squizz
self.assertRaises(RuntimeError, test)
self.assertIs(holder.exc_info[0], RuntimeError)
self.assertIsNotNone(holder.exc_info[1],
'exception value not propgated')
'exception value not propagated')
self.assertIsNotNone(holder.exc_info[2],
'exception traceback not propgated')
'exception traceback not propagated')
def test_create_and_specs(self):
@@ -1822,6 +1816,56 @@ class PatchTest(unittest.TestCase):
self.assertEqual(stopped, ["three", "two", "one"])
def test_patch_dict_stopall(self):
dic1 = {}
dic2 = {1: 'a'}
dic3 = {1: 'A', 2: 'B'}
origdic1 = dic1.copy()
origdic2 = dic2.copy()
origdic3 = dic3.copy()
patch.dict(dic1, {1: 'I', 2: 'II'}).start()
patch.dict(dic2, {2: 'b'}).start()
@patch.dict(dic3)
def patched():
del dic3[1]
patched()
self.assertNotEqual(dic1, origdic1)
self.assertNotEqual(dic2, origdic2)
self.assertEqual(dic3, origdic3)
patch.stopall()
self.assertEqual(dic1, origdic1)
self.assertEqual(dic2, origdic2)
self.assertEqual(dic3, origdic3)
def test_patch_and_patch_dict_stopall(self):
original_unlink = os.unlink
original_chdir = os.chdir
dic1 = {}
dic2 = {1: 'A', 2: 'B'}
origdic1 = dic1.copy()
origdic2 = dic2.copy()
patch('os.unlink', something).start()
patch('os.chdir', something_else).start()
patch.dict(dic1, {1: 'I', 2: 'II'}).start()
patch.dict(dic2).start()
del dic2[1]
self.assertIsNot(os.unlink, original_unlink)
self.assertIsNot(os.chdir, original_chdir)
self.assertNotEqual(dic1, origdic1)
self.assertNotEqual(dic2, origdic2)
patch.stopall()
self.assertIs(os.unlink, original_unlink)
self.assertIs(os.chdir, original_chdir)
self.assertEqual(dic1, origdic1)
self.assertEqual(dic2, origdic2)
def test_special_attrs(self):
def foo(x=0):
@@ -1831,9 +1875,10 @@ class PatchTest(unittest.TestCase):
self.assertEqual(foo(), 1)
self.assertEqual(foo(), 0)
orig_doc = foo.__doc__
with patch.object(foo, '__doc__', "FUN"):
self.assertEqual(foo.__doc__, "FUN")
self.assertEqual(foo.__doc__, "TEST")
self.assertEqual(foo.__doc__, orig_doc)
with patch.object(foo, '__module__', "testpatch2"):
self.assertEqual(foo.__module__, "testpatch2")
@@ -1849,5 +1894,60 @@ class PatchTest(unittest.TestCase):
self.assertEqual(foo(), 1)
self.assertEqual(foo(), 0)
def test_patch_orderdict(self):
foo = OrderedDict()
foo['a'] = object()
foo['b'] = 'python'
original = foo.copy()
update_values = list(zip('cdefghijklmnopqrstuvwxyz', range(26)))
patched_values = list(foo.items()) + update_values
with patch.dict(foo, OrderedDict(update_values)):
self.assertEqual(list(foo.items()), patched_values)
self.assertEqual(foo, original)
with patch.dict(foo, update_values):
self.assertEqual(list(foo.items()), patched_values)
self.assertEqual(foo, original)
def test_dotted_but_module_not_loaded(self):
# This exercises the AttributeError branch of _dot_lookup.
# make sure it's there
import unittest.test.testmock.support
# now make sure it's not:
with patch.dict('sys.modules'):
del sys.modules['unittest.test.testmock.support']
del sys.modules['unittest.test.testmock']
del sys.modules['unittest.test']
del sys.modules['unittest']
# now make sure we can patch based on a dotted path:
@patch('unittest.test.testmock.support.X')
def test(mock):
pass
test()
def test_invalid_target(self):
class Foo:
pass
for target in ['', 12, Foo()]:
with self.subTest(target=target):
with self.assertRaises(TypeError):
patch(target)
def test_cant_set_kwargs_when_passing_a_mock(self):
@patch('unittest.test.testmock.support.X', new=object(), x=1)
def test(): pass
with self.assertRaises(TypeError):
test()
if __name__ == '__main__':
unittest.main()
+64 -8
View File
@@ -3,15 +3,10 @@ from unittest import mock
class SampleObject:
def __init__(self):
self.attr_sample1 = 1
self.attr_sample2 = 1
def method_sample1(self):
pass
def method_sample1(self): pass
def method_sample2(self):
pass
def method_sample2(self): pass
class TestSealable(unittest.TestCase):
@@ -133,7 +128,7 @@ class TestSealable(unittest.TestCase):
m.attr_sample2
def test_integration_with_spec_method_definition(self):
"""You need to defin the methods, even if they are in the spec"""
"""You need to define the methods, even if they are in the spec"""
m = mock.Mock(SampleObject)
m.method_sample1.return_value = 1
@@ -176,6 +171,67 @@ class TestSealable(unittest.TestCase):
m.test1().test2.test3().test4()
self.assertIn("mock.test1().test2.test3().test4", str(cm.exception))
def test_seal_with_autospec(self):
# https://bugs.python.org/issue45156
class Foo:
foo = 0
def bar1(self):
return 1
def bar2(self):
return 2
class Baz:
baz = 3
def ban(self):
return 4
for spec_set in (True, False):
with self.subTest(spec_set=spec_set):
foo = mock.create_autospec(Foo, spec_set=spec_set)
foo.bar1.return_value = 'a'
foo.Baz.ban.return_value = 'b'
mock.seal(foo)
self.assertIsInstance(foo.foo, mock.NonCallableMagicMock)
self.assertIsInstance(foo.bar1, mock.MagicMock)
self.assertIsInstance(foo.bar2, mock.MagicMock)
self.assertIsInstance(foo.Baz, mock.MagicMock)
self.assertIsInstance(foo.Baz.baz, mock.NonCallableMagicMock)
self.assertIsInstance(foo.Baz.ban, mock.MagicMock)
self.assertEqual(foo.bar1(), 'a')
foo.bar1.return_value = 'new_a'
self.assertEqual(foo.bar1(), 'new_a')
self.assertEqual(foo.Baz.ban(), 'b')
foo.Baz.ban.return_value = 'new_b'
self.assertEqual(foo.Baz.ban(), 'new_b')
with self.assertRaises(TypeError):
foo.foo()
with self.assertRaises(AttributeError):
foo.bar = 1
with self.assertRaises(AttributeError):
foo.bar2()
foo.bar2.return_value = 'bar2'
self.assertEqual(foo.bar2(), 'bar2')
with self.assertRaises(AttributeError):
foo.missing_attr
with self.assertRaises(AttributeError):
foo.missing_attr = 1
with self.assertRaises(AttributeError):
foo.missing_method()
with self.assertRaises(TypeError):
foo.Baz.baz()
with self.assertRaises(AttributeError):
foo.Baz.missing_attr
with self.assertRaises(AttributeError):
foo.Baz.missing_attr = 1
with self.assertRaises(AttributeError):
foo.Baz.missing_method()
if __name__ == "__main__":
unittest.main()
+53 -7
View File
@@ -10,6 +10,8 @@ something = sentinel.Something
something_else = sentinel.SomethingElse
class SampleException(Exception): pass
class WithTest(unittest.TestCase):
@@ -20,14 +22,10 @@ class WithTest(unittest.TestCase):
def test_with_statement_exception(self):
try:
with self.assertRaises(SampleException):
with patch('%s.something' % __name__, sentinel.Something2):
self.assertEqual(something, sentinel.Something2, "unpatched")
raise Exception('pow')
except Exception:
pass
else:
self.fail("patch swallowed exception")
raise SampleException()
self.assertEqual(something, sentinel.Something)
@@ -126,6 +124,19 @@ class WithTest(unittest.TestCase):
self.assertEqual(foo, {})
def test_double_patch_instance_method(self):
class C:
def f(self): pass
c = C()
with patch.object(c, 'f', autospec=True) as patch1:
with patch.object(c, 'f', autospec=True) as patch2:
c.f()
self.assertEqual(patch2.call_count, 1)
self.assertEqual(patch1.call_count, 0)
c.f()
self.assertEqual(patch1.call_count, 1)
class TestMockOpen(unittest.TestCase):
@@ -188,6 +199,7 @@ class TestMockOpen(unittest.TestCase):
def test_readline_data(self):
# Check that readline will return all the lines from the fake file
# And that once fully consumed, readline will return an empty string.
mock = mock_open(read_data='foo\nbar\nbaz\n')
with patch('%s.open' % __name__, mock, create=True):
h = open('bar')
@@ -197,6 +209,7 @@ class TestMockOpen(unittest.TestCase):
self.assertEqual(line1, 'foo\n')
self.assertEqual(line2, 'bar\n')
self.assertEqual(line3, 'baz\n')
self.assertEqual(h.readline(), '')
# Check that we properly emulate a file that doesn't end in a newline
mock = mock_open(read_data='foo')
@@ -204,8 +217,36 @@ class TestMockOpen(unittest.TestCase):
h = open('bar')
result = h.readline()
self.assertEqual(result, 'foo')
self.assertEqual(h.readline(), '')
def test_dunder_iter_data(self):
# Check that dunder_iter will return all the lines from the fake file.
mock = mock_open(read_data='foo\nbar\nbaz\n')
with patch('%s.open' % __name__, mock, create=True):
h = open('bar')
lines = [l for l in h]
self.assertEqual(lines[0], 'foo\n')
self.assertEqual(lines[1], 'bar\n')
self.assertEqual(lines[2], 'baz\n')
self.assertEqual(h.readline(), '')
with self.assertRaises(StopIteration):
next(h)
def test_next_data(self):
# Check that next will correctly return the next available
# line and plays well with the dunder_iter part.
mock = mock_open(read_data='foo\nbar\nbaz\n')
with patch('%s.open' % __name__, mock, create=True):
h = open('bar')
line1 = next(h)
line2 = next(h)
lines = [l for l in h]
self.assertEqual(line1, 'foo\n')
self.assertEqual(line2, 'bar\n')
self.assertEqual(lines[0], 'baz\n')
self.assertEqual(h.readline(), '')
def test_readlines_data(self):
# Test that emulating a file that ends in a newline character works
mock = mock_open(read_data='foo\nbar\nbaz\n')
@@ -257,7 +298,12 @@ class TestMockOpen(unittest.TestCase):
# for mocks returned by mock_open
some_data = 'foo\nbar\nbaz'
mock = mock_open(read_data=some_data)
self.assertEqual(mock().read(10), some_data)
self.assertEqual(mock().read(10), some_data[:10])
self.assertEqual(mock().read(10), some_data[:10])
f = mock()
self.assertEqual(f.read(10), some_data[:10])
self.assertEqual(f.read(10), some_data[10:])
def test_interleaved_reads(self):