"""Test case implementation"""
from .util import (strclass, safe_repr, _count_diff_all_purpose,
_count_diff_hashable, _common_shorten_repr)
_subtest_msg_sentinel = object()
DIFF_OMITTED = ('\nDiff is %s characters long. '
'Set self.maxDiff to None to see it.')
class SkipTest(Exception):
Raise this exception in a test to skip it.
Usually you can use TestCase.skipTest() or one of the skipping decorators
instead of raising this directly.
class _ShouldStop(Exception):
class _UnexpectedSuccess(Exception):
The test was supposed to fail, but it didn't!
def __init__(self, result=None):
self.expecting_failure = False
self.result_supports_subtests = hasattr(result, "addSubTest")
self.expectedFailure = None
@contextlib.contextmanager
def testPartExecutor(self, test_case, isTest=False):
old_success = self.success
except KeyboardInterrupt:
self.skipped.append((test_case, str(e)))
exc_info = sys.exc_info()
if self.expecting_failure:
self.expectedFailure = exc_info
self.errors.append((test_case, exc_info))
# explicitly break a reference cycle:
# exc_info -> frame -> exc_info
if self.result_supports_subtests and self.success:
self.errors.append((test_case, None))
self.success = self.success and old_success
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))
"""Execute all module cleanup functions. Normally called for you after
function, args, kwargs = _module_cleanups.pop()
function(*args, **kwargs)
# Swallows all but first exception. If a multi-exception handler
# gets written we should use that here instead.
Unconditionally skip a test.
def decorator(test_item):
if not isinstance(test_item, type):
@functools.wraps(test_item)
def skip_wrapper(*args, **kwargs):
test_item.__unittest_skip__ = True
test_item.__unittest_skip_why__ = reason
if isinstance(reason, types.FunctionType):
return decorator(test_item)
def skipIf(condition, reason):
Skip a test if the condition is true.
def skipUnless(condition, reason):
Skip a test unless the condition is true.
def expectedFailure(test_item):
test_item.__unittest_expecting_failure__ = True
def _is_subtype(expected, basetype):
if isinstance(expected, tuple):
return all(_is_subtype(e, basetype) for e in expected)
return isinstance(expected, type) and issubclass(expected, basetype)
class _BaseTestCaseContext:
def __init__(self, test_case):
self.test_case = test_case
def _raiseFailure(self, standardMsg):
msg = self.test_case._formatMessage(self.msg, standardMsg)
raise self.test_case.failureException(msg)
class _AssertRaisesBaseContext(_BaseTestCaseContext):
def __init__(self, expected, test_case, expected_regex=None):
_BaseTestCaseContext.__init__(self, test_case)
self.test_case = test_case
if expected_regex is not None:
expected_regex = re.compile(expected_regex)
self.expected_regex = expected_regex
def handle(self, name, args, kwargs):
If args is empty, assertRaises/Warns is being used as a
context manager, so check for a 'msg' kwarg and return self.
If args is not empty, call a callable passing positional and keyword
if not _is_subtype(self.expected, self._base_type):
raise TypeError('%s() arg 1 must be %s' %
(name, self._base_type_str))
self.msg = kwargs.pop('msg', None)
raise TypeError('%r is an invalid keyword argument for '
'this function' % (next(iter(kwargs)),))
callable_obj, *args = args
self.obj_name = callable_obj.__name__
self.obj_name = str(callable_obj)
callable_obj(*args, **kwargs)
# bpo-23890: manually break a reference cycle
class _AssertRaisesContext(_AssertRaisesBaseContext):
"""A context manager used to implement TestCase.assertRaises* methods."""
_base_type = BaseException
_base_type_str = 'an exception type or tuple of exception types'
def __exit__(self, exc_type, exc_value, tb):
exc_name = self.expected.__name__
exc_name = str(self.expected)
self._raiseFailure("{} not raised by {}".format(exc_name,
self._raiseFailure("{} not raised".format(exc_name))
traceback.clear_frames(tb)
if not issubclass(exc_type, self.expected):
# let unexpected exceptions pass through
# store exception, without traceback, for later retrieval
self.exception = exc_value.with_traceback(None)
if self.expected_regex is None:
expected_regex = self.expected_regex
if not expected_regex.search(str(exc_value)):
self._raiseFailure('"{}" does not match "{}"'.format(
expected_regex.pattern, str(exc_value)))
class _AssertWarnsContext(_AssertRaisesBaseContext):
"""A context manager used to implement TestCase.assertWarns* methods."""
_base_type_str = 'a warning type or tuple of warning types'
# The __warningregistry__'s need to be in a pristine state for tests
for v in list(sys.modules.values()):
if getattr(v, '__warningregistry__', None):
v.__warningregistry__ = {}
self.warnings_manager = warnings.catch_warnings(record=True)
self.warnings = self.warnings_manager.__enter__()
warnings.simplefilter("always", self.expected)
def __exit__(self, exc_type, exc_value, tb):
self.warnings_manager.__exit__(exc_type, exc_value, tb)
# let unexpected exceptions pass through
exc_name = self.expected.__name__
exc_name = str(self.expected)
if not isinstance(w, self.expected):
if first_matching is None:
if (self.expected_regex is not None and
not self.expected_regex.search(str(w))):
# store warning for later retrieval
self.filename = m.filename
# Now we simply try to choose a helpful failure message
if first_matching is not None:
self._raiseFailure('"{}" does not match "{}"'.format(
self.expected_regex.pattern, str(first_matching)))
self._raiseFailure("{} not triggered by {}".format(exc_name,
self._raiseFailure("{} not triggered".format(exc_name))
_LoggingWatcher = collections.namedtuple("_LoggingWatcher",
class _CapturingHandler(logging.Handler):
A logging handler capturing all (raw and formatted) logging output.
logging.Handler.__init__(self)
self.watcher = _LoggingWatcher([], [])
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
self.level = logging._nameToLevel.get(level, level)
self.level = logging.INFO
if isinstance(self.logger_name, logging.Logger):
logger = self.logger = self.logger_name
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)
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)
# let unexpected exceptions pass through
if len(self.watcher.records) == 0:
"no logs of level {} or higher triggered on {}"
.format(logging.getLevelName(self.level), self.logger.name))
class _OrderedChainMap(collections.ChainMap):
for mapping in self.maps:
"""A class whose instances are single test cases.
By default, the test code itself should be placed in a method named
If the fixture may be used for many test cases, create as
many test methods as are needed. When instantiating such a TestCase
subclass, specify in the constructor arguments the name of the test method
that the instance is to execute.
Test authors should subclass TestCase for their own tests. Construction
and deconstruction of the test's environment ('fixture') can be
implemented by overriding the 'setUp' and 'tearDown' methods respectively.
If it is necessary to override the __init__ method, the base class
__init__ method must always be called. It is important that subclasses
should not change the signature of their __init__ method, since instances
of the classes are instantiated automatically by parts of the framework
When subclassing TestCase, you can set these attributes:
* failureException: determines which exception will be raised when
the instance's assertion methods fail; test methods raising this
exception will be deemed to have 'failed' rather than 'errored'.
* longMessage: determines whether long messages (including repr of
objects used in assert methods) will be printed on failure in *addition*
to any explicit message passed.
* maxDiff: sets the maximum length of a diff in failure messages
by assert methods using difflib. It is looked up as an instance
attribute so can be configured by individual tests if required.
failureException = AssertionError
# If a string is longer than _diffThreshold, use normal comparison instead
# of difflib. See #11763.
# Attribute used by TestSuite for classSetUp
_classSetupFailed = False
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
not have a method with the specified name.
self._testMethodName = methodName
self._testMethodDoc = 'No test'
testMethod = getattr(self, methodName)
if methodName != 'runTest':
# we allow instantiation with no explicit method name
# but not an *incorrect* or missing method name
raise ValueError("no such test method in %s: %s" %
(self.__class__, methodName))
self._testMethodDoc = testMethod.__doc__
# Map types to custom assertEqual functions that will compare
# instances of said type in more detail to generate a more useful
self._type_equality_funcs = {}
self.addTypeEqualityFunc(dict, 'assertDictEqual')
self.addTypeEqualityFunc(list, 'assertListEqual')
self.addTypeEqualityFunc(tuple, 'assertTupleEqual')
self.addTypeEqualityFunc(set, 'assertSetEqual')
self.addTypeEqualityFunc(frozenset, 'assertSetEqual')
self.addTypeEqualityFunc(str, 'assertMultiLineEqual')
def addTypeEqualityFunc(self, typeobj, function):
"""Add a type specific assertEqual style function to compare a type.
This method is for use by TestCase subclasses that need to register
their own type equality functions to provide nicer error messages.
typeobj: The data type to call this function on when both values
are of the same type in assertEqual().
function: The callable taking two arguments and an optional
msg= argument that raises self.failureException with a
useful error message when the two arguments are not equal.
self._type_equality_funcs[typeobj] = function
def addCleanup(*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.
Cleanup items are called even if setUp fails (unlike tearDown)."""
self, function, *args = args
raise TypeError("descriptor 'addCleanup' of 'TestCase' object "
elif 'function' in kwargs:
function = kwargs.pop('function')
warnings.warn("Passing 'function' as keyword argument is deprecated",
DeprecationWarning, stacklevel=2)
raise TypeError('addCleanup expected at least 1 positional '
'argument, got %d' % (len(args)-1))
self._cleanups.append((function, args, kwargs))
addCleanup.__text_signature__ = '($self, function, /, *args, **kwargs)'
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))