aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/unittest
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/unittest')
-rw-r--r--Lib/unittest/case.py531
-rw-r--r--Lib/unittest/loader.py57
-rw-r--r--Lib/unittest/main.py119
-rw-r--r--Lib/unittest/result.py7
-rw-r--r--Lib/unittest/runner.py45
-rw-r--r--Lib/unittest/suite.py12
-rw-r--r--Lib/unittest/test/_test_warnings.py74
-rw-r--r--Lib/unittest/test/support.py45
-rw-r--r--Lib/unittest/test/test_assertions.py46
-rw-r--r--Lib/unittest/test/test_break.py12
-rw-r--r--Lib/unittest/test/test_case.py522
-rw-r--r--Lib/unittest/test/test_discovery.py69
-rw-r--r--Lib/unittest/test/test_functiontestcase.py14
-rw-r--r--Lib/unittest/test/test_loader.py58
-rw-r--r--Lib/unittest/test/test_program.py115
-rw-r--r--Lib/unittest/test/test_result.py45
-rw-r--r--Lib/unittest/test/test_runner.py123
-rw-r--r--Lib/unittest/test/test_setups.py7
-rw-r--r--Lib/unittest/test/test_skipping.py21
-rw-r--r--Lib/unittest/test/test_suite.py15
-rw-r--r--Lib/unittest/util.py30
21 files changed, 1294 insertions, 673 deletions
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
index 6257936618a..bea810711db 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -1,20 +1,17 @@
"""Test case implementation"""
-import collections
import sys
import functools
import difflib
import pprint
import re
-import types
import warnings
+import collections
from . import result
-from .util import (
- strclass, safe_repr, unorderable_list_difference,
- _count_diff_all_purpose, _count_diff_hashable
-)
-
+from .util import (strclass, safe_repr, sorted_list_difference,
+ unorderable_list_difference, _count_diff_all_purpose,
+ _count_diff_hashable)
__unittest = True
@@ -29,7 +26,6 @@ class SkipTest(Exception):
Usually you can use TestResult.skip() or one of the skipping decorators
instead of raising this directly.
"""
- pass
class _ExpectedFailure(Exception):
"""
@@ -46,7 +42,17 @@ class _UnexpectedSuccess(Exception):
"""
The test was supposed to fail, but it didn't!
"""
- pass
+
+
+class _Outcome(object):
+ def __init__(self):
+ self.success = True
+ self.skipped = None
+ self.unexpectedSuccess = None
+ self.expectedFailure = None
+ self.errors = []
+ self.failures = []
+
def _id(obj):
return obj
@@ -56,7 +62,7 @@ def skip(reason):
Unconditionally skip a test.
"""
def decorator(test_item):
- if not isinstance(test_item, (type, types.ClassType)):
+ if not isinstance(test_item, type):
@functools.wraps(test_item)
def skip_wrapper(*args, **kwargs):
raise SkipTest(reason)
@@ -95,13 +101,26 @@ def expectedFailure(func):
return wrapper
-class _AssertRaisesContext(object):
- """A context manager used to implement TestCase.assertRaises* methods."""
+class _AssertRaisesBaseContext(object):
- def __init__(self, expected, test_case, expected_regexp=None):
+ def __init__(self, expected, test_case, callable_obj=None,
+ expected_regex=None):
self.expected = expected
self.failureException = test_case.failureException
- self.expected_regexp = expected_regexp
+ if callable_obj is not None:
+ try:
+ self.obj_name = callable_obj.__name__
+ except AttributeError:
+ self.obj_name = str(callable_obj)
+ else:
+ self.obj_name = None
+ if isinstance(expected_regex, (bytes, str)):
+ expected_regex = re.compile(expected_regex)
+ self.expected_regex = expected_regex
+
+
+class _AssertRaisesContext(_AssertRaisesBaseContext):
+ """A context manager used to implement TestCase.assertRaises* methods."""
def __enter__(self):
return self
@@ -112,24 +131,77 @@ class _AssertRaisesContext(object):
exc_name = self.expected.__name__
except AttributeError:
exc_name = str(self.expected)
- raise self.failureException(
- "{0} not raised".format(exc_name))
+ if self.obj_name:
+ raise self.failureException("{0} not raised by {1}"
+ .format(exc_name, self.obj_name))
+ else:
+ raise self.failureException("{0} not raised"
+ .format(exc_name))
if not issubclass(exc_type, self.expected):
# let unexpected exceptions pass through
return False
- self.exception = exc_value # store for later retrieval
- if self.expected_regexp is None:
+ # store exception, without traceback, for later retrieval
+ self.exception = exc_value.with_traceback(None)
+ if self.expected_regex is None:
return True
- expected_regexp = self.expected_regexp
- if isinstance(expected_regexp, basestring):
- expected_regexp = re.compile(expected_regexp)
- if not expected_regexp.search(str(exc_value)):
+ expected_regex = self.expected_regex
+ if not expected_regex.search(str(exc_value)):
raise self.failureException('"%s" does not match "%s"' %
- (expected_regexp.pattern, str(exc_value)))
+ (expected_regex.pattern, str(exc_value)))
return True
+class _AssertWarnsContext(_AssertRaisesBaseContext):
+ """A context manager used to implement TestCase.assertWarns* methods."""
+
+ def __enter__(self):
+ # The __warningregistry__'s need to be in a pristine state for tests
+ # to work properly.
+ for v in 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)
+ return self
+
+ def __exit__(self, exc_type, exc_value, tb):
+ self.warnings_manager.__exit__(exc_type, exc_value, tb)
+ if exc_type is not None:
+ # let unexpected exceptions pass through
+ return
+ try:
+ exc_name = self.expected.__name__
+ except AttributeError:
+ exc_name = str(self.expected)
+ first_matching = None
+ for m in self.warnings:
+ w = m.message
+ if not isinstance(w, self.expected):
+ continue
+ if first_matching is None:
+ first_matching = w
+ if (self.expected_regex is not None and
+ not self.expected_regex.search(str(w))):
+ continue
+ # store warning for later retrieval
+ self.warning = w
+ self.filename = m.filename
+ self.lineno = m.lineno
+ return
+ # Now we simply try to choose a helpful failure message
+ if first_matching is not None:
+ raise self.failureException('"%s" does not match "%s"' %
+ (self.expected_regex.pattern, str(first_matching)))
+ if self.obj_name:
+ raise self.failureException("{0} not triggered by {1}"
+ .format(exc_name, self.obj_name))
+ else:
+ raise self.failureException("{0} not triggered"
+ .format(exc_name))
+
+
class TestCase(object):
"""A class whose instances are single test cases.
@@ -162,7 +234,7 @@ class TestCase(object):
# objects used in assert methods) will be printed on failure in *addition*
# to any explicit message passed.
- longMessage = False
+ longMessage = True
# This attribute sets the maximum length of a diff in failure messages
# by assert methods using difflib. It is looked up as an instance attribute
@@ -184,13 +256,18 @@ class TestCase(object):
not have a method with the specified name.
"""
self._testMethodName = methodName
- self._resultForDoCleanups = None
+ self._outcomeForDoCleanups = None
+ self._testMethodDoc = 'No test'
try:
testMethod = getattr(self, methodName)
except AttributeError:
- raise ValueError("no such test method in %s: %s" %
- (self.__class__, methodName))
- self._testMethodDoc = testMethod.__doc__
+ 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))
+ else:
+ self._testMethodDoc = testMethod.__doc__
self._cleanups = []
# Map types to custom assertEqual functions that will compare
@@ -202,11 +279,7 @@ class TestCase(object):
self.addTypeEqualityFunc(tuple, 'assertTupleEqual')
self.addTypeEqualityFunc(set, 'assertSetEqual')
self.addTypeEqualityFunc(frozenset, 'assertSetEqual')
- try:
- self.addTypeEqualityFunc(unicode, 'assertMultiLineEqual')
- except NameError:
- # No unicode support in this build
- pass
+ self.addTypeEqualityFunc(str, 'assertMultiLineEqual')
def addTypeEqualityFunc(self, typeobj, function):
"""Add a type specific assertEqual style function to compare a type.
@@ -273,9 +346,6 @@ class TestCase(object):
return self._testMethodName == other._testMethodName
- def __ne__(self, other):
- return not self == other
-
def __hash__(self):
return hash((type(self), self._testMethodName))
@@ -295,6 +365,36 @@ class TestCase(object):
RuntimeWarning, 2)
result.addSuccess(self)
+ def _executeTestPart(self, function, outcome, isTest=False):
+ try:
+ function()
+ except KeyboardInterrupt:
+ raise
+ except SkipTest as e:
+ outcome.success = False
+ outcome.skipped = str(e)
+ except _UnexpectedSuccess:
+ exc_info = sys.exc_info()
+ outcome.success = False
+ if isTest:
+ outcome.unexpectedSuccess = exc_info
+ else:
+ outcome.errors.append(exc_info)
+ except _ExpectedFailure:
+ outcome.success = False
+ exc_info = sys.exc_info()
+ if isTest:
+ outcome.expectedFailure = exc_info
+ else:
+ outcome.errors.append(exc_info)
+ except self.failureException:
+ outcome.success = False
+ outcome.failures.append(sys.exc_info())
+ exc_info = sys.exc_info()
+ except:
+ outcome.success = False
+ outcome.errors.append(sys.exc_info())
+
def run(self, result=None):
orig_result = result
if result is None:
@@ -303,7 +403,6 @@ class TestCase(object):
if startTestRun is not None:
startTestRun()
- self._resultForDoCleanups = result
result.startTest(self)
testMethod = getattr(self, self._testMethodName)
@@ -318,57 +417,42 @@ class TestCase(object):
result.stopTest(self)
return
try:
- success = False
- try:
- self.setUp()
- except SkipTest as e:
- self._addSkip(result, str(e))
- except KeyboardInterrupt:
- raise
- except:
- result.addError(self, sys.exc_info())
+ outcome = _Outcome()
+ self._outcomeForDoCleanups = outcome
+
+ self._executeTestPart(self.setUp, outcome)
+ if outcome.success:
+ self._executeTestPart(testMethod, outcome, isTest=True)
+ self._executeTestPart(self.tearDown, outcome)
+
+ self.doCleanups()
+ if outcome.success:
+ result.addSuccess(self)
else:
- try:
- testMethod()
- except KeyboardInterrupt:
- raise
- except self.failureException:
- result.addFailure(self, sys.exc_info())
- except _ExpectedFailure as e:
- addExpectedFailure = getattr(result, 'addExpectedFailure', None)
- if addExpectedFailure is not None:
- addExpectedFailure(self, e.exc_info)
- else:
- warnings.warn("TestResult has no addExpectedFailure method, reporting as passes",
- RuntimeWarning)
- result.addSuccess(self)
- except _UnexpectedSuccess:
+ if outcome.skipped is not None:
+ self._addSkip(result, outcome.skipped)
+ for exc_info in outcome.errors:
+ result.addError(self, exc_info)
+ for exc_info in outcome.failures:
+ result.addFailure(self, exc_info)
+ if outcome.unexpectedSuccess is not None:
addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None)
if addUnexpectedSuccess is not None:
addUnexpectedSuccess(self)
else:
warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failures",
RuntimeWarning)
- result.addFailure(self, sys.exc_info())
- except SkipTest as e:
- self._addSkip(result, str(e))
- except:
- result.addError(self, sys.exc_info())
- else:
- success = True
+ result.addFailure(self, outcome.unexpectedSuccess)
+
+ if outcome.expectedFailure is not None:
+ addExpectedFailure = getattr(result, 'addExpectedFailure', None)
+ if addExpectedFailure is not None:
+ addExpectedFailure(self, outcome.expectedFailure)
+ else:
+ warnings.warn("TestResult has no addExpectedFailure method, reporting as passes",
+ RuntimeWarning)
+ result.addSuccess(self)
- try:
- self.tearDown()
- except KeyboardInterrupt:
- raise
- except:
- result.addError(self, sys.exc_info())
- success = False
-
- cleanUpSuccess = self.doCleanups()
- success = success and cleanUpSuccess
- if success:
- result.addSuccess(self)
finally:
result.stopTest(self)
if orig_result is None:
@@ -379,18 +463,15 @@ class TestCase(object):
def doCleanups(self):
"""Execute all cleanup functions. Normally called for you after
tearDown."""
- result = self._resultForDoCleanups
- ok = True
+ outcome = self._outcomeForDoCleanups or _Outcome()
while self._cleanups:
- function, args, kwargs = self._cleanups.pop(-1)
- try:
- function(*args, **kwargs)
- except KeyboardInterrupt:
- raise
- except:
- ok = False
- result.addError(self, sys.exc_info())
- return ok
+ function, args, kwargs = self._cleanups.pop()
+ part = lambda: function(*args, **kwargs)
+ self._executeTestPart(part, outcome)
+
+ # return this for backwards compatibility
+ # even though we no longer us it internally
+ return outcome.success
def __call__(self, *args, **kwds):
return self.run(*args, **kwds)
@@ -469,12 +550,43 @@ class TestCase(object):
the_exception = cm.exception
self.assertEqual(the_exception.error_code, 3)
"""
- context = _AssertRaisesContext(excClass, self)
+ context = _AssertRaisesContext(excClass, self, callableObj)
if callableObj is None:
return context
with context:
callableObj(*args, **kwargs)
+ def assertWarns(self, expected_warning, callable_obj=None, *args, **kwargs):
+ """Fail unless a warning of class warnClass is triggered
+ by callableObj when invoked with arguments args and keyword
+ arguments kwargs. If a different type of warning is
+ triggered, it will not be handled: depending on the other
+ warning filtering rules in effect, it might be silenced, printed
+ out, or raised as an exception.
+
+ If called with callableObj omitted or None, will return a
+ context object used like this::
+
+ with self.assertWarns(SomeWarning):
+ do_something()
+
+ The context manager keeps a reference to the first matching
+ warning as the 'warning' attribute; similarly, the 'filename'
+ and 'lineno' attributes give you information about the line
+ of Python code from which the warning was triggered.
+ This allows you to inspect the warning after the assertion::
+
+ with self.assertWarns(SomeWarning) as cm:
+ do_something()
+ the_warning = cm.warning
+ self.assertEqual(the_warning.some_attribute, 147)
+ """
+ context = _AssertWarnsContext(expected_warning, self, callable_obj)
+ if callable_obj is None:
+ return context
+ with context:
+ callable_obj(*args, **kwargs)
+
def _getAssertEqualityFunc(self, first, second):
"""Get a detailed comparison function for the types of the two args.
@@ -495,7 +607,7 @@ class TestCase(object):
if type(first) is type(second):
asserter = self._type_equality_funcs.get(type(first))
if asserter is not None:
- if isinstance(asserter, basestring):
+ if isinstance(asserter, str):
asserter = getattr(self, asserter)
return asserter
@@ -524,8 +636,8 @@ class TestCase(object):
safe_repr(second)))
raise self.failureException(msg)
-
- def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None):
+ def assertAlmostEqual(self, first, second, places=None, msg=None,
+ delta=None):
"""Fail if the two objects are unequal as determined by their
difference rounded to the given number of decimal places
(default 7) and comparing to zero, or by comparing that the
@@ -563,7 +675,8 @@ class TestCase(object):
msg = self._formatMessage(msg, standardMsg)
raise self.failureException(msg)
- def assertNotAlmostEqual(self, first, second, places=None, msg=None, delta=None):
+ def assertNotAlmostEqual(self, first, second, places=None, msg=None,
+ delta=None):
"""Fail if the two objects are equal as determined by their
difference rounded to the given number of decimal places
(default 7) and comparing to zero, or by comparing that the
@@ -594,34 +707,6 @@ class TestCase(object):
msg = self._formatMessage(msg, standardMsg)
raise self.failureException(msg)
- # Synonyms for assertion methods
-
- # The plurals are undocumented. Keep them that way to discourage use.
- # Do not add more. Do not remove.
- # Going through a deprecation cycle on these would annoy many people.
- assertEquals = assertEqual
- assertNotEquals = assertNotEqual
- assertAlmostEquals = assertAlmostEqual
- assertNotAlmostEquals = assertNotAlmostEqual
- assert_ = assertTrue
-
- # These fail* assertion method names are pending deprecation and will
- # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578
- def _deprecate(original_func):
- def deprecated_func(*args, **kwargs):
- warnings.warn(
- 'Please use {0} instead.'.format(original_func.__name__),
- PendingDeprecationWarning, 2)
- return original_func(*args, **kwargs)
- return deprecated_func
-
- failUnlessEqual = _deprecate(assertEqual)
- failIfEqual = _deprecate(assertNotEqual)
- failUnlessAlmostEqual = _deprecate(assertAlmostEqual)
- failIfAlmostEqual = _deprecate(assertNotAlmostEqual)
- failUnless = _deprecate(assertTrue)
- failUnlessRaises = _deprecate(assertRaises)
- failIf = _deprecate(assertFalse)
def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
"""An equality assertion for ordered sequences (like lists and tuples).
@@ -637,7 +722,7 @@ class TestCase(object):
msg: Optional message to use on failure instead of a list of
differences.
"""
- if seq_type is not None:
+ if seq_type != None:
seq_type_name = seq_type.__name__
if not isinstance(seq1, seq_type):
raise self.failureException('First sequence is not a %s: %s'
@@ -675,7 +760,7 @@ class TestCase(object):
elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr)
differing = '%ss differ: %s != %s\n' % elements
- for i in xrange(min(len1, len2)):
+ for i in range(min(len1, len2)):
try:
item1 = seq1[i]
except (TypeError, IndexError, NotImplementedError):
@@ -722,6 +807,7 @@ class TestCase(object):
diffMsg = '\n' + '\n'.join(
difflib.ndiff(pprint.pformat(seq1).splitlines(),
pprint.pformat(seq2).splitlines()))
+
standardMsg = self._truncateMessage(standardMsg, diffMsg)
msg = self._formatMessage(msg, standardMsg)
self.fail(msg)
@@ -770,16 +856,16 @@ class TestCase(object):
"""
try:
difference1 = set1.difference(set2)
- except TypeError, e:
+ except TypeError as e:
self.fail('invalid type when attempting set difference: %s' % e)
- except AttributeError, e:
+ except AttributeError as e:
self.fail('first argument does not support set difference: %s' % e)
try:
difference2 = set2.difference(set1)
- except TypeError, e:
+ except TypeError as e:
self.fail('invalid type when attempting set difference: %s' % e)
- except AttributeError, e:
+ except AttributeError as e:
self.fail('second argument does not support set difference: %s' % e)
if not (difference1 or difference2):
@@ -837,17 +923,19 @@ class TestCase(object):
standardMsg = self._truncateMessage(standardMsg, diff)
self.fail(self._formatMessage(msg, standardMsg))
- def assertDictContainsSubset(self, expected, actual, msg=None):
- """Checks whether actual is a superset of expected."""
+ def assertDictContainsSubset(self, subset, dictionary, msg=None):
+ """Checks whether dictionary is a superset of subset."""
+ warnings.warn('assertDictContainsSubset is deprecated',
+ DeprecationWarning)
missing = []
mismatched = []
- for key, value in expected.iteritems():
- if key not in actual:
+ for key, value in subset.items():
+ if key not in dictionary:
missing.append(key)
- elif value != actual[key]:
+ elif value != dictionary[key]:
mismatched.append('%s, expected: %s, actual: %s' %
(safe_repr(key), safe_repr(value),
- safe_repr(actual[key])))
+ safe_repr(dictionary[key])))
if not (missing or mismatched):
return
@@ -863,37 +951,73 @@ class TestCase(object):
self.fail(self._formatMessage(msg, standardMsg))
- def assertItemsEqual(self, expected_seq, actual_seq, msg=None):
- """An unordered sequence specific comparison. It asserts that
- actual_seq and expected_seq have the same element counts.
- Equivalent to::
+ def assertSameElements(self, expected_seq, actual_seq, msg=None):
+ """An unordered sequence specific comparison.
- self.assertEqual(Counter(iter(actual_seq)),
- Counter(iter(expected_seq)))
+ Raises with an error message listing which elements of expected_seq
+ are missing from actual_seq and vice versa if any.
- Asserts that each element has the same count in both sequences.
- Example:
- - [0, 1, 1] and [1, 0, 1] compare equal.
- - [0, 0, 1] and [0, 1] compare unequal.
+ Duplicate elements are ignored when comparing *expected_seq* and
+ *actual_seq*. It is the equivalent of ``assertEqual(set(expected),
+ set(actual))`` but it works with sequences of unhashable objects as
+ well.
"""
- first_seq, second_seq = list(expected_seq), list(actual_seq)
- with warnings.catch_warnings():
- if sys.py3kwarning:
- # Silence Py3k warning raised during the sorting
- for _msg in ["(code|dict|type) inequality comparisons",
- "builtin_function_or_method order comparisons",
- "comparing unequal types"]:
- warnings.filterwarnings("ignore", _msg, DeprecationWarning)
+ warnings.warn('assertSameElements is deprecated',
+ DeprecationWarning)
+ try:
+ expected = set(expected_seq)
+ actual = set(actual_seq)
+ missing = sorted(expected.difference(actual))
+ unexpected = sorted(actual.difference(expected))
+ except TypeError:
+ # Fall back to slower list-compare if any of the objects are
+ # not hashable.
+ expected = list(expected_seq)
+ actual = list(actual_seq)
try:
- first = collections.Counter(first_seq)
- second = collections.Counter(second_seq)
+ expected.sort()
+ actual.sort()
except TypeError:
- # Handle case with unhashable elements
- differences = _count_diff_all_purpose(first_seq, second_seq)
+ missing, unexpected = unorderable_list_difference(expected,
+ actual)
else:
- if first == second:
- return
- differences = _count_diff_hashable(first_seq, second_seq)
+ missing, unexpected = sorted_list_difference(expected, actual)
+ errors = []
+ if missing:
+ errors.append('Expected, but missing:\n %s' %
+ safe_repr(missing))
+ if unexpected:
+ errors.append('Unexpected, but present:\n %s' %
+ safe_repr(unexpected))
+ if errors:
+ standardMsg = '\n'.join(errors)
+ self.fail(self._formatMessage(msg, standardMsg))
+
+
+ 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.
+
+ self.assertEqual(Counter(list(first)),
+ Counter(list(second)))
+
+ Example:
+ - [0, 1, 1] and [1, 0, 1] compare equal.
+ - [0, 0, 1] and [0, 1] compare unequal.
+
+ """
+ first_seq, second_seq = list(first), list(second)
+ try:
+ first = collections.Counter(first_seq)
+ second = collections.Counter(second_seq)
+ except TypeError:
+ # Handle case with unhashable elements
+ differences = _count_diff_all_purpose(first_seq, second_seq)
+ else:
+ if first == second:
+ return
+ differences = _count_diff_hashable(first_seq, second_seq)
if differences:
standardMsg = 'Element counts were not equal:\n'
@@ -905,10 +1029,8 @@ class TestCase(object):
def assertMultiLineEqual(self, first, second, msg=None):
"""Assert that two multi-line strings are equal."""
- self.assertIsInstance(first, basestring,
- 'First argument is not a string')
- self.assertIsInstance(second, basestring,
- 'Second argument is not a string')
+ self.assertIsInstance(first, str, 'First argument is not a string')
+ self.assertIsInstance(second, str, 'Second argument is not a string')
if first != second:
# don't use difflib if the strings are too long
@@ -975,47 +1097,92 @@ class TestCase(object):
standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls)
self.fail(self._formatMessage(msg, standardMsg))
- def assertRaisesRegexp(self, expected_exception, expected_regexp,
- callable_obj=None, *args, **kwargs):
- """Asserts that the message in a raised exception matches a regexp.
+ def assertRaisesRegex(self, expected_exception, expected_regex,
+ callable_obj=None, *args, **kwargs):
+ """Asserts that the message in a raised exception matches a regex.
Args:
expected_exception: Exception class expected to be raised.
- expected_regexp: Regexp (re pattern object or string) expected
+ expected_regex: Regex (re pattern object or string) expected
+ to be found in error message.
+ callable_obj: Function to be called.
+ args: Extra args.
+ kwargs: Extra kwargs.
+ """
+ context = _AssertRaisesContext(expected_exception, self, callable_obj,
+ expected_regex)
+ if callable_obj is None:
+ return context
+ with context:
+ callable_obj(*args, **kwargs)
+
+ def assertWarnsRegex(self, expected_warning, expected_regex,
+ callable_obj=None, *args, **kwargs):
+ """Asserts that the message in a triggered warning matches a regexp.
+ Basic functioning is similar to assertWarns() with the addition
+ that only warnings whose messages also match the regular expression
+ are considered successful matches.
+
+ Args:
+ expected_warning: Warning class expected to be triggered.
+ expected_regex: Regex (re pattern object or string) expected
to be found in error message.
callable_obj: Function to be called.
args: Extra args.
kwargs: Extra kwargs.
"""
- context = _AssertRaisesContext(expected_exception, self, expected_regexp)
+ context = _AssertWarnsContext(expected_warning, self, callable_obj,
+ expected_regex)
if callable_obj is None:
return context
with context:
callable_obj(*args, **kwargs)
- def assertRegexpMatches(self, text, expected_regexp, msg=None):
+ def assertRegex(self, text, expected_regex, msg=None):
"""Fail the test unless the text matches the regular expression."""
- if isinstance(expected_regexp, basestring):
- expected_regexp = re.compile(expected_regexp)
- if not expected_regexp.search(text):
- msg = msg or "Regexp didn't match"
- msg = '%s: %r not found in %r' % (msg, expected_regexp.pattern, text)
+ if isinstance(expected_regex, (str, bytes)):
+ assert expected_regex, "expected_regex must not be empty."
+ expected_regex = re.compile(expected_regex)
+ if not expected_regex.search(text):
+ msg = msg or "Regex didn't match"
+ msg = '%s: %r not found in %r' % (msg, expected_regex.pattern, text)
raise self.failureException(msg)
- def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None):
+ def assertNotRegex(self, text, unexpected_regex, msg=None):
"""Fail the test if the text matches the regular expression."""
- if isinstance(unexpected_regexp, basestring):
- unexpected_regexp = re.compile(unexpected_regexp)
- match = unexpected_regexp.search(text)
+ if isinstance(unexpected_regex, (str, bytes)):
+ unexpected_regex = re.compile(unexpected_regex)
+ match = unexpected_regex.search(text)
if match:
- msg = msg or "Regexp matched"
+ msg = msg or "Regex matched"
msg = '%s: %r matches %r in %r' % (msg,
text[match.start():match.end()],
- unexpected_regexp.pattern,
+ unexpected_regex.pattern,
text)
raise self.failureException(msg)
+ def _deprecate(original_func):
+ def deprecated_func(*args, **kwargs):
+ warnings.warn(
+ 'Please use {0} instead.'.format(original_func.__name__),
+ DeprecationWarning, 2)
+ return original_func(*args, **kwargs)
+ return deprecated_func
+
+ # see #9424
+ failUnlessEqual = assertEquals = _deprecate(assertEqual)
+ failIfEqual = assertNotEquals = _deprecate(assertNotEqual)
+ failUnlessAlmostEqual = assertAlmostEquals = _deprecate(assertAlmostEqual)
+ failIfAlmostEqual = assertNotAlmostEquals = _deprecate(assertNotAlmostEqual)
+ failUnless = assert_ = _deprecate(assertTrue)
+ failUnlessRaises = _deprecate(assertRaises)
+ failIf = _deprecate(assertFalse)
+ assertRaisesRegexp = _deprecate(assertRaisesRegex)
+ assertRegexpMatches = _deprecate(assertRegex)
+
+
+
class FunctionTestCase(TestCase):
"""A test case that wraps a test function.
diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py
index e88f536b394..541884e4161 100644
--- a/Lib/unittest/loader.py
+++ b/Lib/unittest/loader.py
@@ -5,11 +5,11 @@ import re
import sys
import traceback
import types
+import functools
-from functools import cmp_to_key as _CmpToKey
from fnmatch import fnmatch
-from . import case, suite
+from . import case, suite, util
__unittest = True
@@ -34,6 +34,11 @@ def _make_failed_test(classname, methodname, exception, suiteClass):
TestClass = type(classname, (case.TestCase,), attrs)
return suiteClass((TestClass(methodname),))
+def _jython_aware_splitext(path):
+ if path.lower().endswith('$py.class'):
+ return path[:-9]
+ return os.path.splitext(path)[0]
+
class TestLoader(object):
"""
@@ -41,7 +46,7 @@ class TestLoader(object):
and returning them wrapped in a TestSuite
"""
testMethodPrefix = 'test'
- sortTestMethodsUsing = cmp
+ sortTestMethodsUsing = staticmethod(util.three_way_cmp)
suiteClass = suite.TestSuite
_top_level_dir = None
@@ -69,7 +74,7 @@ class TestLoader(object):
if use_load_tests and load_tests is not None:
try:
return load_tests(self, tests, None)
- except Exception, e:
+ except Exception as e:
return _make_failed_load_tests(module.__name__, e,
self.suiteClass)
return tests
@@ -103,13 +108,17 @@ class TestLoader(object):
return self.loadTestsFromModule(obj)
elif isinstance(obj, type) and issubclass(obj, case.TestCase):
return self.loadTestsFromTestCase(obj)
- elif (isinstance(obj, types.UnboundMethodType) and
+ elif (isinstance(obj, types.FunctionType) and
isinstance(parent, type) and
issubclass(parent, case.TestCase)):
- return self.suiteClass([parent(obj.__name__)])
+ name = obj.__name__
+ inst = parent(name)
+ # static methods follow a different path
+ if not isinstance(getattr(inst, name), types.FunctionType):
+ return self.suiteClass([inst])
elif isinstance(obj, suite.TestSuite):
return obj
- elif hasattr(obj, '__call__'):
+ if callable(obj):
test = obj()
if isinstance(test, suite.TestSuite):
return test
@@ -134,17 +143,17 @@ class TestLoader(object):
def isTestMethod(attrname, testCaseClass=testCaseClass,
prefix=self.testMethodPrefix):
return attrname.startswith(prefix) and \
- hasattr(getattr(testCaseClass, attrname), '__call__')
- testFnNames = filter(isTestMethod, dir(testCaseClass))
+ callable(getattr(testCaseClass, attrname))
+ testFnNames = list(filter(isTestMethod, dir(testCaseClass)))
if self.sortTestMethodsUsing:
- testFnNames.sort(key=_CmpToKey(self.sortTestMethodsUsing))
+ testFnNames.sort(key=functools.cmp_to_key(self.sortTestMethodsUsing))
return testFnNames
def discover(self, start_dir, pattern='test*.py', top_level_dir=None):
"""Find and return all test modules from the specified start
- directory, recursing into subdirectories to find them. Only test files
- that match the pattern will be loaded. (Using shell style pattern
- matching.)
+ directory, recursing into subdirectories to find them and return all
+ tests found within them. Only test files that match the pattern will
+ be loaded. (Using shell style pattern matching.)
All test modules must be importable from the top level of the project.
If the start directory is not the top level directory then the top
@@ -217,7 +226,7 @@ class TestLoader(object):
return os.path.dirname(full_path)
def _get_name_from_path(self, path):
- path = os.path.splitext(os.path.normpath(path))[0]
+ path = _jython_aware_splitext(os.path.normpath(path))
_relpath = os.path.relpath(path, self._top_level_dir)
assert not os.path.isabs(_relpath), "Path must be within the project"
@@ -254,11 +263,11 @@ class TestLoader(object):
yield _make_failed_import_test(name, self.suiteClass)
else:
mod_file = os.path.abspath(getattr(module, '__file__', full_path))
- realpath = os.path.splitext(mod_file)[0]
- fullpath_noext = os.path.splitext(full_path)[0]
+ realpath = _jython_aware_splitext(mod_file)
+ fullpath_noext = _jython_aware_splitext(full_path)
if realpath.lower() != fullpath_noext.lower():
module_dir = os.path.dirname(realpath)
- mod_name = os.path.splitext(os.path.basename(full_path))[0]
+ mod_name = _jython_aware_splitext(os.path.basename(full_path))
expected_dir = os.path.dirname(full_path)
msg = ("%r module incorrectly imported from %r. Expected %r. "
"Is this module globally installed?")
@@ -287,7 +296,7 @@ class TestLoader(object):
else:
try:
yield load_tests(self, tests, pattern)
- except Exception, e:
+ except Exception as e:
yield _make_failed_load_tests(package.__name__, e,
self.suiteClass)
@@ -302,13 +311,15 @@ def _makeLoader(prefix, sortUsing, suiteClass=None):
loader.suiteClass = suiteClass
return loader
-def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp):
+def getTestCaseNames(testCaseClass, prefix, sortUsing=util.three_way_cmp):
return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
-def makeSuite(testCaseClass, prefix='test', sortUsing=cmp,
+def makeSuite(testCaseClass, prefix='test', sortUsing=util.three_way_cmp,
suiteClass=suite.TestSuite):
- return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass)
+ return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(
+ testCaseClass)
-def findTestCases(module, prefix='test', sortUsing=cmp,
+def findTestCases(module, prefix='test', sortUsing=util.three_way_cmp,
suiteClass=suite.TestSuite):
- return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module)
+ return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(\
+ module)
diff --git a/Lib/unittest/main.py b/Lib/unittest/main.py
index 3396bb0ab69..55d4e4be148 100644
--- a/Lib/unittest/main.py
+++ b/Lib/unittest/main.py
@@ -58,7 +58,24 @@ Examples:
in MyTestCase
"""
+def _convert_name(name):
+ # on Linux / Mac OS X 'foo.PY' is not importable, but on
+ # Windows it is. Simpler to do a case insensitive match
+ # a better check would be to check that the name is a
+ # valid Python module name.
+ if os.path.isfile(name) and name.lower().endswith('.py'):
+ if os.path.isabs(name):
+ rel_path = os.path.relpath(name, os.getcwd())
+ if os.path.isabs(rel_path) or rel_path.startswith(os.pardir):
+ return 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 name
+def _convert_names(names):
+ return [_convert_name(name) for name in names]
class TestProgram(object):
"""A command-line program that runs a set of tests; this is primarily
@@ -67,13 +84,13 @@ class TestProgram(object):
USAGE = USAGE_FROM_MODULE
# defaults for testing
- failfast = catchbreak = buffer = progName = None
+ failfast = catchbreak = buffer = progName = warnings = None
def __init__(self, module='__main__', defaultTest=None, argv=None,
testRunner=None, testLoader=loader.defaultTestLoader,
exit=True, verbosity=1, failfast=None, catchbreak=None,
- buffer=None):
- if isinstance(module, basestring):
+ buffer=None, warnings=None):
+ if isinstance(module, str):
self.module = __import__(module)
for part in module.split('.')[1:]:
self.module = getattr(self.module, part)
@@ -87,6 +104,18 @@ class TestProgram(object):
self.catchbreak = catchbreak
self.verbosity = verbosity
self.buffer = buffer
+ if warnings is None and not sys.warnoptions:
+ # even if DreprecationWarnings are ignored by default
+ # print them anyway unless other warnings settings are
+ # specified by the warnings arg or the -W python flag
+ self.warnings = 'default'
+ else:
+ # here self.warnings is set either to the value passed
+ # to the warnings args or to None.
+ # If the user didn't pass a value self.warnings will
+ # be None. This means that the behavior is unchanged
+ # and depends on the values passed to -W.
+ self.warnings = warnings
self.defaultTest = defaultTest
self.testRunner = testRunner
self.testLoader = testLoader
@@ -96,7 +125,7 @@ class TestProgram(object):
def usageExit(self, msg=None):
if msg:
- print msg
+ print(msg)
usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
'buffer': ''}
if self.failfast != False:
@@ -105,11 +134,12 @@ class TestProgram(object):
usage['catchbreak'] = CATCHBREAK
if self.buffer != False:
usage['buffer'] = BUFFEROUTPUT
- print self.USAGE % usage
+ print(self.USAGE % usage)
sys.exit(2)
def parseArgs(self, argv):
- if len(argv) > 1 and argv[1].lower() == 'discover':
+ if ((len(argv) > 1 and argv[1].lower() == 'discover') or
+ (len(argv) == 1 and self.module is None)):
self._do_discovery(argv[2:])
return
@@ -117,38 +147,48 @@ class TestProgram(object):
long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']
try:
options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
- for opt, value in options:
- if opt in ('-h','-H','--help'):
- self.usageExit()
- if opt in ('-q','--quiet'):
- self.verbosity = 0
- if opt in ('-v','--verbose'):
- self.verbosity = 2
- if opt in ('-f','--failfast'):
- if self.failfast is None:
- self.failfast = True
- # Should this raise an exception if -f is not valid?
- if opt in ('-c','--catch'):
- if self.catchbreak is None:
- self.catchbreak = True
- # Should this raise an exception if -c is not valid?
- if opt in ('-b','--buffer'):
- if self.buffer is None:
- self.buffer = True
- # Should this raise an exception if -b is not valid?
- if len(args) == 0 and self.defaultTest is None:
- # createTests will load tests from self.module
- self.testNames = None
- elif len(args) > 0:
- self.testNames = args
- if __name__ == '__main__':
- # to support python -m unittest ...
- self.module = None
- else:
- self.testNames = (self.defaultTest,)
- self.createTests()
- except getopt.error, msg:
+ except getopt.error as msg:
self.usageExit(msg)
+ return
+
+ for opt, value in options:
+ if opt in ('-h','-H','--help'):
+ self.usageExit()
+ if opt in ('-q','--quiet'):
+ self.verbosity = 0
+ if opt in ('-v','--verbose'):
+ self.verbosity = 2
+ if opt in ('-f','--failfast'):
+ if self.failfast is None:
+ self.failfast = True
+ # Should this raise an exception if -f is not valid?
+ if opt in ('-c','--catch'):
+ if self.catchbreak is None:
+ self.catchbreak = True
+ # Should this raise an exception if -c is not valid?
+ if opt in ('-b','--buffer'):
+ if self.buffer is None:
+ self.buffer = True
+ # Should this raise an exception if -b is not valid?
+
+ if len(args) == 0 and self.module is None:
+ # this allows "python -m unittest -v" to still work for
+ # test discovery. This means -c / -b / -v / -f options will
+ # be handled twice, which is harmless but not ideal.
+ self._do_discovery(argv[1:])
+ return
+
+ if len(args) == 0 and self.defaultTest is None:
+ # createTests will load tests from self.module
+ self.testNames = None
+ elif len(args) > 0:
+ self.testNames = _convert_names(args)
+ if __name__ == '__main__':
+ # to support python -m unittest ...
+ self.module = None
+ else:
+ self.testNames = (self.defaultTest,)
+ self.createTests()
def createTests(self):
if self.testNames is None:
@@ -215,11 +255,12 @@ class TestProgram(object):
installHandler()
if self.testRunner is None:
self.testRunner = runner.TextTestRunner
- if isinstance(self.testRunner, (type, types.ClassType)):
+ if isinstance(self.testRunner, type):
try:
testRunner = self.testRunner(verbosity=self.verbosity,
failfast=self.failfast,
- buffer=self.buffer)
+ buffer=self.buffer,
+ warnings=self.warnings)
except TypeError:
# didn't accept the verbosity, buffer or failfast arguments
testRunner = self.testRunner()
diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py
index 2cc17d71c85..44bf1862e4f 100644
--- a/Lib/unittest/result.py
+++ b/Lib/unittest/result.py
@@ -1,11 +1,10 @@
"""Test result object"""
import os
+import io
import sys
import traceback
-from StringIO import StringIO
-
from . import util
from functools import wraps
@@ -65,8 +64,8 @@ class TestResult(object):
def _setupStdout(self):
if self.buffer:
if self._stderr_buffer is None:
- self._stderr_buffer = StringIO()
- self._stdout_buffer = StringIO()
+ self._stderr_buffer = io.StringIO()
+ self._stdout_buffer = io.StringIO()
sys.stdout = self._stdout_buffer
sys.stderr = self._stderr_buffer
diff --git a/Lib/unittest/runner.py b/Lib/unittest/runner.py
index 7632fe9823c..28b8865978a 100644
--- a/Lib/unittest/runner.py
+++ b/Lib/unittest/runner.py
@@ -2,6 +2,7 @@
import sys
import time
+import warnings
from . import result
from .signals import registerResult
@@ -124,13 +125,16 @@ class TextTestRunner(object):
"""
resultclass = TextTestResult
- def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1,
- failfast=False, buffer=False, resultclass=None):
+ def __init__(self, stream=None, descriptions=True, verbosity=1,
+ failfast=False, buffer=False, resultclass=None, warnings=None):
+ if stream is None:
+ stream = sys.stderr
self.stream = _WritelnDecorator(stream)
self.descriptions = descriptions
self.verbosity = verbosity
self.failfast = failfast
self.buffer = buffer
+ self.warnings = warnings
if resultclass is not None:
self.resultclass = resultclass
@@ -143,17 +147,30 @@ class TextTestRunner(object):
registerResult(result)
result.failfast = self.failfast
result.buffer = self.buffer
- startTime = time.time()
- startTestRun = getattr(result, 'startTestRun', None)
- if startTestRun is not None:
- startTestRun()
- try:
- test(result)
- finally:
- stopTestRun = getattr(result, 'stopTestRun', None)
- if stopTestRun is not None:
- stopTestRun()
- stopTime = time.time()
+ with warnings.catch_warnings():
+ if self.warnings:
+ # if self.warnings is set, use it to filter all the warnings
+ warnings.simplefilter(self.warnings)
+ # if the filter is 'default' or 'always', special-case the
+ # warnings from the deprecated unittest methods to show them
+ # no more than once per module, because they can be fairly
+ # noisy. The -Wd and -Wa flags can be used to bypass this
+ # only when self.warnings is None.
+ if self.warnings in ['default', 'always']:
+ warnings.filterwarnings('module',
+ category=DeprecationWarning,
+ message='Please use assert\w+ instead.')
+ startTime = time.time()
+ startTestRun = getattr(result, 'startTestRun', None)
+ if startTestRun is not None:
+ startTestRun()
+ try:
+ test(result)
+ finally:
+ stopTestRun = getattr(result, 'stopTestRun', None)
+ if stopTestRun is not None:
+ stopTestRun()
+ stopTime = time.time()
timeTaken = stopTime - startTime
result.printErrors()
if hasattr(result, 'separator2'):
@@ -176,7 +193,7 @@ class TextTestRunner(object):
infos = []
if not result.wasSuccessful():
self.stream.write("FAILED")
- failed, errored = map(len, (result.failures, result.errors))
+ failed, errored = len(result.failures), len(result.errors)
if failed:
infos.append("failures=%d" % failed)
if errored:
diff --git a/Lib/unittest/suite.py b/Lib/unittest/suite.py
index 633af5cb085..cde5d385ed1 100644
--- a/Lib/unittest/suite.py
+++ b/Lib/unittest/suite.py
@@ -31,9 +31,6 @@ class BaseTestSuite(object):
def __ne__(self, other):
return not self == other
- # Can't guarantee hash invariant, so flag as unhashable
- __hash__ = None
-
def __iter__(self):
return iter(self._tests)
@@ -45,7 +42,7 @@ class BaseTestSuite(object):
def addTest(self, test):
# sanity checks
- if not hasattr(test, '__call__'):
+ if not callable(test):
raise TypeError("{} is not callable".format(repr(test)))
if isinstance(test, type) and issubclass(test,
(case.TestCase, TestSuite)):
@@ -54,7 +51,7 @@ class BaseTestSuite(object):
self._tests.append(test)
def addTests(self, tests):
- if isinstance(tests, basestring):
+ if isinstance(tests, str):
raise TypeError("tests must be an iterable of tests, not a string")
for test in tests:
self.addTest(test)
@@ -170,6 +167,7 @@ class TestSuite(BaseTestSuite):
self._handleModuleTearDown(result)
+
result._moduleSetUpFailed = False
try:
module = sys.modules[currentModule]
@@ -180,7 +178,7 @@ class TestSuite(BaseTestSuite):
_call_if_exists(result, '_setupStdout')
try:
setUpModule()
- except Exception, e:
+ except Exception as e:
if isinstance(result, _DebugResult):
raise
result._moduleSetUpFailed = True
@@ -239,7 +237,7 @@ class TestSuite(BaseTestSuite):
_call_if_exists(result, '_setupStdout')
try:
tearDownClass()
- except Exception, e:
+ except Exception as e:
if isinstance(result, _DebugResult):
raise
className = util.strclass(previousClass)
diff --git a/Lib/unittest/test/_test_warnings.py b/Lib/unittest/test/_test_warnings.py
new file mode 100644
index 00000000000..d0be18d4add
--- /dev/null
+++ b/Lib/unittest/test/_test_warnings.py
@@ -0,0 +1,74 @@
+# helper module for test_runner.Test_TextTestRunner.test_warnings
+
+"""
+This module has a number of tests that raise different kinds of warnings.
+When the tests are run, the warnings are caught and their messages are printed
+to stdout. This module also accepts an arg that is then passed to
+unittest.main to affect the behavior of warnings.
+Test_TextTestRunner.test_warnings executes this script with different
+combinations of warnings args and -W flags and check that the output is correct.
+See #10535.
+"""
+
+import io
+import sys
+import unittest
+import warnings
+
+def warnfun():
+ warnings.warn('rw', RuntimeWarning)
+
+class TestWarnings(unittest.TestCase):
+ # unittest warnings will be printed at most once per type (max one message
+ # for the fail* methods, and one for the assert* methods)
+ def test_assert(self):
+ self.assertEquals(2+2, 4)
+ self.assertEquals(2*2, 4)
+ self.assertEquals(2**2, 4)
+
+ def test_fail(self):
+ self.failUnless(1)
+ self.failUnless(True)
+
+ def test_other_unittest(self):
+ self.assertAlmostEqual(2+2, 4)
+ self.assertNotAlmostEqual(4+4, 2)
+
+ # these warnings are normally silenced, but they are printed in unittest
+ def test_deprecation(self):
+ warnings.warn('dw', DeprecationWarning)
+ warnings.warn('dw', DeprecationWarning)
+ warnings.warn('dw', DeprecationWarning)
+
+ def test_import(self):
+ warnings.warn('iw', ImportWarning)
+ warnings.warn('iw', ImportWarning)
+ warnings.warn('iw', ImportWarning)
+
+ # user warnings should always be printed
+ def test_warning(self):
+ warnings.warn('uw')
+ warnings.warn('uw')
+ warnings.warn('uw')
+
+ # these warnings come from the same place; they will be printed
+ # only once by default or three times if the 'always' filter is used
+ def test_function(self):
+
+ warnfun()
+ warnfun()
+ warnfun()
+
+
+
+if __name__ == '__main__':
+ with warnings.catch_warnings(record=True) as ws:
+ # if an arg is provided pass it to unittest.main as 'warnings'
+ if len(sys.argv) == 2:
+ unittest.main(exit=False, warnings=sys.argv.pop())
+ else:
+ unittest.main(exit=False)
+
+ # print all the warning messages collected
+ for w in ws:
+ print(w.message)
diff --git a/Lib/unittest/test/support.py b/Lib/unittest/test/support.py
index f1cf03b1420..dbe4ddcd0e7 100644
--- a/Lib/unittest/test/support.py
+++ b/Lib/unittest/test/support.py
@@ -1,6 +1,21 @@
import unittest
+class TestEquality(object):
+ """Used as a mixin for TestCase"""
+
+ # Check for a valid __eq__ implementation
+ def test_eq(self):
+ for obj_1, obj_2 in self.eq_pairs:
+ self.assertEqual(obj_1, obj_2)
+ self.assertEqual(obj_2, obj_1)
+
+ # Check for a valid __ne__ implementation
+ def test_ne(self):
+ for obj_1, obj_2 in self.ne_pairs:
+ self.assertNotEqual(obj_1, obj_2)
+ self.assertNotEqual(obj_2, obj_1)
+
class TestHashing(object):
"""Used as a mixin for TestCase"""
@@ -12,7 +27,7 @@ class TestHashing(object):
self.fail("%r and %r do not hash equal" % (obj_1, obj_2))
except KeyboardInterrupt:
raise
- except Exception, e:
+ except Exception as e:
self.fail("Problem hashing %r and %r: %s" % (obj_1, obj_2, e))
for obj_1, obj_2 in self.ne_pairs:
@@ -22,34 +37,18 @@ class TestHashing(object):
(obj_1, obj_2))
except KeyboardInterrupt:
raise
- except Exception, e:
+ except Exception as e:
self.fail("Problem hashing %s and %s: %s" % (obj_1, obj_2, e))
-class TestEquality(object):
- """Used as a mixin for TestCase"""
-
- # Check for a valid __eq__ implementation
- def test_eq(self):
- for obj_1, obj_2 in self.eq_pairs:
- self.assertEqual(obj_1, obj_2)
- self.assertEqual(obj_2, obj_1)
-
- # Check for a valid __ne__ implementation
- def test_ne(self):
- for obj_1, obj_2 in self.ne_pairs:
- self.assertNotEqual(obj_1, obj_2)
- self.assertNotEqual(obj_2, obj_1)
-
-
class LoggingResult(unittest.TestResult):
def __init__(self, log):
self._events = log
- super(LoggingResult, self).__init__()
+ super().__init__()
def startTest(self, test):
self._events.append('startTest')
- super(LoggingResult, self).startTest(test)
+ super().startTest(test)
def startTestRun(self):
self._events.append('startTestRun')
@@ -57,7 +56,7 @@ class LoggingResult(unittest.TestResult):
def stopTest(self, test):
self._events.append('stopTest')
- super(LoggingResult, self).stopTest(test)
+ super().stopTest(test)
def stopTestRun(self):
self._events.append('stopTestRun')
@@ -65,7 +64,7 @@ class LoggingResult(unittest.TestResult):
def addFailure(self, *args):
self._events.append('addFailure')
- super(LoggingResult, self).addFailure(*args)
+ super().addFailure(*args)
def addSuccess(self, *args):
self._events.append('addSuccess')
@@ -73,7 +72,7 @@ class LoggingResult(unittest.TestResult):
def addError(self, *args):
self._events.append('addError')
- super(LoggingResult, self).addError(*args)
+ super().addError(*args)
def addSkip(self, *args):
self._events.append('addSkip')
diff --git a/Lib/unittest/test/test_assertions.py b/Lib/unittest/test/test_assertions.py
index e1ba6147066..a1d20ebf2da 100644
--- a/Lib/unittest/test/test_assertions.py
+++ b/Lib/unittest/test/test_assertions.py
@@ -1,5 +1,5 @@
import datetime
-
+import warnings
import unittest
@@ -58,7 +58,7 @@ class Test_Assertions(unittest.TestCase):
try:
self.assertRaises(KeyError, lambda: None)
except self.failureException as e:
- self.assertIn("KeyError not raised", e.args)
+ self.assertIn("KeyError not raised", str(e))
else:
self.fail("assertRaises() didn't fail")
try:
@@ -70,9 +70,10 @@ class Test_Assertions(unittest.TestCase):
with self.assertRaises(KeyError) as cm:
try:
raise KeyError
- except Exception, e:
+ except Exception as e:
+ exc = e
raise
- self.assertIs(cm.exception, e)
+ self.assertIs(cm.exception, exc)
with self.assertRaises(KeyError):
raise KeyError("key")
@@ -80,7 +81,7 @@ class Test_Assertions(unittest.TestCase):
with self.assertRaises(KeyError):
pass
except self.failureException as e:
- self.assertIn("KeyError not raised", e.args)
+ self.assertIn("KeyError not raised", str(e))
else:
self.fail("assertRaises() didn't fail")
try:
@@ -91,15 +92,15 @@ class Test_Assertions(unittest.TestCase):
else:
self.fail("assertRaises() didn't let exception pass through")
- def testAssertNotRegexpMatches(self):
- self.assertNotRegexpMatches('Ala ma kota', r'r+')
+ def testAssertNotRegex(self):
+ self.assertNotRegex('Ala ma kota', r'r+')
try:
- self.assertNotRegexpMatches('Ala ma kota', r'k.t', 'Message')
- except self.failureException, e:
+ self.assertNotRegex('Ala ma kota', r'k.t', 'Message')
+ except self.failureException as e:
self.assertIn("'kot'", e.args[0])
self.assertIn('Message', e.args[0])
else:
- self.fail('assertNotRegexpMatches should have failed.')
+ self.fail('assertNotRegex should have failed.')
class TestLongMessage(unittest.TestCase):
@@ -126,7 +127,7 @@ class TestLongMessage(unittest.TestCase):
self.testableFalse = TestableTestFalse('testTest')
def testDefault(self):
- self.assertFalse(unittest.TestCase.longMessage)
+ self.assertTrue(unittest.TestCase.longMessage)
def test_formatMsg(self):
self.assertEqual(self.testableFalse._formatMessage(None, "foo"), "foo")
@@ -141,7 +142,7 @@ class TestLongMessage(unittest.TestCase):
def test_formatMessage_unicode_error(self):
one = ''.join(chr(i) for i in range(255))
# this used to cause a UnicodeDecodeError constructing msg
- self.testableTrue._formatMessage(one, u'\uFFFD')
+ self.testableTrue._formatMessage(one, '\uFFFD')
def assertMessages(self, methodName, args, errors):
def getMethod(i):
@@ -152,15 +153,15 @@ class TestLongMessage(unittest.TestCase):
test = self.testableTrue
return getattr(test, methodName)
- for i, expected_regexp in enumerate(errors):
+ for i, expected_regex in enumerate(errors):
testMethod = getMethod(i)
kwargs = {}
withMsg = i % 2
if withMsg:
kwargs = {"msg": "oops"}
- with self.assertRaisesRegexp(self.failureException,
- expected_regexp=expected_regexp):
+ with self.assertRaisesRegex(self.failureException,
+ expected_regex=expected_regex):
testMethod(*args, **kwargs)
def testAssertTrue(self):
@@ -223,10 +224,13 @@ class TestLongMessage(unittest.TestCase):
"\+ \{'key': 'value'\} : oops$"])
def testAssertDictContainsSubset(self):
- self.assertMessages('assertDictContainsSubset', ({'key': 'value'}, {}),
- ["^Missing: 'key'$", "^oops$",
- "^Missing: 'key'$",
- "^Missing: 'key' : oops$"])
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore", DeprecationWarning)
+
+ self.assertMessages('assertDictContainsSubset', ({'key': 'value'}, {}),
+ ["^Missing: 'key'$", "^oops$",
+ "^Missing: 'key'$",
+ "^Missing: 'key' : oops$"])
def testAssertMultiLineEqual(self):
self.assertMessages('assertMultiLineEqual', ("", "foo"),
@@ -280,7 +284,3 @@ class TestLongMessage(unittest.TestCase):
["^unexpectedly identical: None$", "^oops$",
"^unexpectedly identical: None$",
"^unexpectedly identical: None : oops$"])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/Lib/unittest/test/test_break.py b/Lib/unittest/test/test_break.py
index 560001103f8..77ce20143bf 100644
--- a/Lib/unittest/test/test_break.py
+++ b/Lib/unittest/test/test_break.py
@@ -1,12 +1,10 @@
import gc
+import io
import os
import sys
import signal
import weakref
-from cStringIO import StringIO
-
-
import unittest
@@ -144,7 +142,7 @@ class TestBreak(unittest.TestCase):
def testRunner(self):
# Creating a TextTestRunner with the appropriate argument should
# register the TextTestResult it creates
- runner = unittest.TextTestRunner(stream=StringIO())
+ runner = unittest.TextTestRunner(stream=io.StringIO())
result = runner.run(unittest.TestSuite())
self.assertIn(result, unittest.signals._results)
@@ -211,7 +209,8 @@ class TestBreak(unittest.TestCase):
self.assertEqual(FakeRunner.initArgs, [((), {'buffer': None,
'verbosity': verbosity,
- 'failfast': failfast})])
+ 'failfast': failfast,
+ 'warnings': None})])
self.assertEqual(FakeRunner.runArgs, [test])
self.assertEqual(p.result, result)
@@ -224,7 +223,8 @@ class TestBreak(unittest.TestCase):
self.assertEqual(FakeRunner.initArgs, [((), {'buffer': None,
'verbosity': verbosity,
- 'failfast': failfast})])
+ 'failfast': failfast,
+ 'warnings': None})])
self.assertEqual(FakeRunner.runArgs, [test])
self.assertEqual(p.result, result)
diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py
index e92b0191674..c74a539515a 100644
--- a/Lib/unittest/test/test_case.py
+++ b/Lib/unittest/test/test_case.py
@@ -3,14 +3,17 @@ import pprint
import pickle
import re
import sys
+import warnings
+import inspect
from copy import deepcopy
-from test import test_support
+from test import support
import unittest
from .support import (
- TestEquality, TestHashing, LoggingResult, ResultWithNoStartTestRunStopTestRun
+ TestEquality, TestHashing, LoggingResult,
+ ResultWithNoStartTestRunStopTestRun
)
@@ -50,9 +53,9 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
eq_pairs = [(Test.Foo('test1'), Test.Foo('test1'))]
# Used by TestEquality.test_ne
- ne_pairs = [(Test.Foo('test1'), Test.Foo('runTest'))
- ,(Test.Foo('test1'), Test.Bar('test1'))
- ,(Test.Foo('test1'), Test.Bar('test2'))]
+ ne_pairs = [(Test.Foo('test1'), Test.Foo('runTest')),
+ (Test.Foo('test1'), Test.Bar('test1')),
+ (Test.Foo('test1'), Test.Bar('test2'))]
################################################################
### /Set up attributes used by inherited tests
@@ -69,18 +72,28 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
# thing.
def test_init__no_test_name(self):
class Test(unittest.TestCase):
- def runTest(self): raise TypeError()
+ def runTest(self): raise MyException()
def test(self): pass
self.assertEqual(Test().id()[-13:], '.Test.runTest')
+ # test that TestCase can be instantiated with no args
+ # primarily for use at the interactive interpreter
+ test = unittest.TestCase()
+ test.assertEqual(3, 3)
+ with test.assertRaises(test.failureException):
+ test.assertEqual(3, 2)
+
+ with self.assertRaises(AttributeError):
+ test.run()
+
# "class TestCase([methodName])"
# ...
# "Each instance of TestCase will run a single test method: the
# method named methodName."
def test_init__test_name__valid(self):
class Test(unittest.TestCase):
- def runTest(self): raise TypeError()
+ def runTest(self): raise MyException()
def test(self): pass
self.assertEqual(Test('test').id()[-10:], '.Test.test')
@@ -91,7 +104,7 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
# method named methodName."
def test_init__test_name__invalid(self):
class Test(unittest.TestCase):
- def runTest(self): raise TypeError()
+ def runTest(self): raise MyException()
def test(self): pass
try:
@@ -174,8 +187,8 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
super(Foo, self).test()
raise RuntimeError('raised by Foo.test')
- expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown',
- 'stopTest']
+ expected = ['startTest', 'setUp', 'test', 'tearDown',
+ 'addError', 'stopTest']
Foo(events).run(result)
self.assertEqual(events, expected)
@@ -192,8 +205,8 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
super(Foo, self).test()
raise RuntimeError('raised by Foo.test')
- expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addError',
- 'tearDown', 'stopTest', 'stopTestRun']
+ expected = ['startTestRun', 'startTest', 'setUp', 'test',
+ 'tearDown', 'addError', 'stopTest', 'stopTestRun']
Foo(events).run()
self.assertEqual(events, expected)
@@ -213,8 +226,8 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
super(Foo, self).test()
self.fail('raised by Foo.test')
- expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown',
- 'stopTest']
+ expected = ['startTest', 'setUp', 'test', 'tearDown',
+ 'addFailure', 'stopTest']
Foo(events).run(result)
self.assertEqual(events, expected)
@@ -228,8 +241,8 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
super(Foo, self).test()
self.fail('raised by Foo.test')
- expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addFailure',
- 'tearDown', 'stopTest', 'stopTestRun']
+ expected = ['startTestRun', 'startTest', 'setUp', 'test',
+ 'tearDown', 'addFailure', 'stopTest', 'stopTestRun']
events = []
Foo(events).run()
self.assertEqual(events, expected)
@@ -370,7 +383,8 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
def runTest(self):
pass
- self.assertIsInstance(Foo().id(), basestring)
+ self.assertIsInstance(Foo().id(), str)
+
# "If result is omitted or None, a temporary result object is created
# and used, but is not made available to the caller. As TestCase owns the
@@ -422,9 +436,9 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
class SadSnake(object):
"""Dummy class for test_addTypeEqualityFunc."""
s1, s2 = SadSnake(), SadSnake()
- self.assertNotEqual(s1, s2)
+ self.assertFalse(s1 == s2)
def AllSnakesCreatedEqual(a, b, msg=None):
- return type(a) is type(b) is SadSnake
+ return type(a) == type(b) == SadSnake
self.addTypeEqualityFunc(SadSnake, AllSnakesCreatedEqual)
self.assertEqual(s1, s2)
# No this doesn't clean up and remove the SadSnake equality func
@@ -475,32 +489,34 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
animals)
def testAssertDictContainsSubset(self):
- self.assertDictContainsSubset({}, {})
- self.assertDictContainsSubset({}, {'a': 1})
- self.assertDictContainsSubset({'a': 1}, {'a': 1})
- self.assertDictContainsSubset({'a': 1}, {'a': 1, 'b': 2})
- self.assertDictContainsSubset({'a': 1, 'b': 2}, {'a': 1, 'b': 2})
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore", DeprecationWarning)
- with self.assertRaises(self.failureException):
- self.assertDictContainsSubset({1: "one"}, {})
+ self.assertDictContainsSubset({}, {})
+ self.assertDictContainsSubset({}, {'a': 1})
+ self.assertDictContainsSubset({'a': 1}, {'a': 1})
+ self.assertDictContainsSubset({'a': 1}, {'a': 1, 'b': 2})
+ self.assertDictContainsSubset({'a': 1, 'b': 2}, {'a': 1, 'b': 2})
- with self.assertRaises(self.failureException):
- self.assertDictContainsSubset({'a': 2}, {'a': 1})
+ with self.assertRaises(self.failureException):
+ self.assertDictContainsSubset({1: "one"}, {})
- with self.assertRaises(self.failureException):
- self.assertDictContainsSubset({'c': 1}, {'a': 1})
+ with self.assertRaises(self.failureException):
+ self.assertDictContainsSubset({'a': 2}, {'a': 1})
- with self.assertRaises(self.failureException):
- self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1})
+ with self.assertRaises(self.failureException):
+ self.assertDictContainsSubset({'c': 1}, {'a': 1})
- with self.assertRaises(self.failureException):
- self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1})
+ with self.assertRaises(self.failureException):
+ self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1})
+
+ with self.assertRaises(self.failureException):
+ self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1})
- with test_support.check_warnings(("", UnicodeWarning)):
one = ''.join(chr(i) for i in range(255))
# this used to cause a UnicodeDecodeError constructing the failure msg
with self.assertRaises(self.failureException):
- self.assertDictContainsSubset({'foo': one}, {'foo': u'\uFFFD'})
+ self.assertDictContainsSubset({'foo': one}, {'foo': '\uFFFD'})
def testAssertEqual(self):
equal_pairs = [
@@ -602,6 +618,7 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
self.maxDiff = len(diff)//2
try:
+
self.assertSequenceEqual(seq1, seq2)
except self.failureException as e:
msg = e.args[0]
@@ -680,14 +697,14 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
self.addCleanup(lambda: setattr(self, '_diffThreshold', old_threshold))
# under the threshold: diff marker (^) in error message
- s = u'x' * (2**7)
+ s = 'x' * (2**7)
with self.assertRaises(self.failureException) as cm:
self.assertEqual(s + 'a', s + 'b')
self.assertIn('^', str(cm.exception))
self.assertEqual(s + 'a', s + 'a')
# over the threshold: diff not used and marker (^) not in error message
- s = u'x' * (2**9)
+ s = 'x' * (2**9)
# if the path that uses difflib is taken, _truncateMessage will be
# called -- replace it with explodingTruncation to verify that this
# doesn't happen
@@ -704,56 +721,56 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
self.assertEqual(str(cm.exception), '%r != %r' % (s1, s2))
self.assertEqual(s + 'a', s + 'a')
- def testAssertItemsEqual(self):
+ def testAssertCountEqual(self):
a = object()
- self.assertItemsEqual([1, 2, 3], [3, 2, 1])
- self.assertItemsEqual(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo'])
- self.assertItemsEqual([a, a, 2, 2, 3], (a, 2, 3, a, 2))
- self.assertItemsEqual([1, "2", "a", "a"], ["a", "2", True, "a"])
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertCountEqual([1, 2, 3], [3, 2, 1])
+ self.assertCountEqual(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo'])
+ self.assertCountEqual([a, a, 2, 2, 3], (a, 2, 3, a, 2))
+ self.assertCountEqual([1, "2", "a", "a"], ["a", "2", True, "a"])
+ self.assertRaises(self.failureException, self.assertCountEqual,
[1, 2] + [3] * 100, [1] * 100 + [2, 3])
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertRaises(self.failureException, self.assertCountEqual,
[1, "2", "a", "a"], ["a", "2", True, 1])
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertRaises(self.failureException, self.assertCountEqual,
[10], [10, 11])
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertRaises(self.failureException, self.assertCountEqual,
[10, 11], [10])
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertRaises(self.failureException, self.assertCountEqual,
[10, 11, 10], [10, 11])
# Test that sequences of unhashable objects can be tested for sameness:
- self.assertItemsEqual([[1, 2], [3, 4], 0], [False, [3, 4], [1, 2]])
+ self.assertCountEqual([[1, 2], [3, 4], 0], [False, [3, 4], [1, 2]])
# Test that iterator of unhashable objects can be tested for sameness:
- self.assertItemsEqual(iter([1, 2, [], 3, 4]),
+ self.assertCountEqual(iter([1, 2, [], 3, 4]),
iter([1, 2, [], 3, 4]))
# hashable types, but not orderable
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertRaises(self.failureException, self.assertCountEqual,
[], [divmod, 'x', 1, 5j, 2j, frozenset()])
# comparing dicts
- self.assertItemsEqual([{'a': 1}, {'b': 2}], [{'b': 2}, {'a': 1}])
+ self.assertCountEqual([{'a': 1}, {'b': 2}], [{'b': 2}, {'a': 1}])
# comparing heterogenous non-hashable sequences
- self.assertItemsEqual([1, 'x', divmod, []], [divmod, [], 'x', 1])
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertCountEqual([1, 'x', divmod, []], [divmod, [], 'x', 1])
+ self.assertRaises(self.failureException, self.assertCountEqual,
[], [divmod, [], 'x', 1, 5j, 2j, set()])
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertRaises(self.failureException, self.assertCountEqual,
[[1]], [[2]])
# Same elements, but not same sequence length
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertRaises(self.failureException, self.assertCountEqual,
[1, 1, 2], [2, 1])
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertRaises(self.failureException, self.assertCountEqual,
[1, 1, "2", "a", "a"], ["2", "2", True, "a"])
- self.assertRaises(self.failureException, self.assertItemsEqual,
+ self.assertRaises(self.failureException, self.assertCountEqual,
[1, {'b': 2}, None, True], [{'b': 2}, True, None])
# Same elements which don't reliably compare, in
# different order, see issue 10242
a = [{2,4}, {1,2}]
b = a[::-1]
- self.assertItemsEqual(a, b)
+ self.assertCountEqual(a, b)
- # test utility functions supporting assertItemsEqual()
+ # test utility functions supporting assertCountEqual()
diffs = set(unittest.util._count_diff_all_purpose('aaabccd', 'abbbcce'))
expected = {(3,1,'a'), (1,3,'b'), (1,0,'d'), (0,1,'e')}
@@ -849,62 +866,34 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
self.assertRaises(self.failureException, self.assertLess, 'ant', 'ant')
self.assertRaises(self.failureException, self.assertLessEqual, 'bug', 'ant')
- # Try Unicode
- self.assertGreater(u'bug', u'ant')
- self.assertGreaterEqual(u'bug', u'ant')
- self.assertGreaterEqual(u'ant', u'ant')
- self.assertLess(u'ant', u'bug')
- self.assertLessEqual(u'ant', u'bug')
- self.assertLessEqual(u'ant', u'ant')
- self.assertRaises(self.failureException, self.assertGreater, u'ant', u'bug')
- self.assertRaises(self.failureException, self.assertGreater, u'ant', u'ant')
- self.assertRaises(self.failureException, self.assertGreaterEqual, u'ant',
- u'bug')
- self.assertRaises(self.failureException, self.assertLess, u'bug', u'ant')
- self.assertRaises(self.failureException, self.assertLess, u'ant', u'ant')
- self.assertRaises(self.failureException, self.assertLessEqual, u'bug', u'ant')
-
- # Try Mixed String/Unicode
- self.assertGreater('bug', u'ant')
- self.assertGreater(u'bug', 'ant')
- self.assertGreaterEqual('bug', u'ant')
- self.assertGreaterEqual(u'bug', 'ant')
- self.assertGreaterEqual('ant', u'ant')
- self.assertGreaterEqual(u'ant', 'ant')
- self.assertLess('ant', u'bug')
- self.assertLess(u'ant', 'bug')
- self.assertLessEqual('ant', u'bug')
- self.assertLessEqual(u'ant', 'bug')
- self.assertLessEqual('ant', u'ant')
- self.assertLessEqual(u'ant', 'ant')
- self.assertRaises(self.failureException, self.assertGreater, 'ant', u'bug')
- self.assertRaises(self.failureException, self.assertGreater, u'ant', 'bug')
- self.assertRaises(self.failureException, self.assertGreater, 'ant', u'ant')
- self.assertRaises(self.failureException, self.assertGreater, u'ant', 'ant')
- self.assertRaises(self.failureException, self.assertGreaterEqual, 'ant',
- u'bug')
- self.assertRaises(self.failureException, self.assertGreaterEqual, u'ant',
- 'bug')
- self.assertRaises(self.failureException, self.assertLess, 'bug', u'ant')
- self.assertRaises(self.failureException, self.assertLess, u'bug', 'ant')
- self.assertRaises(self.failureException, self.assertLess, 'ant', u'ant')
- self.assertRaises(self.failureException, self.assertLess, u'ant', 'ant')
- self.assertRaises(self.failureException, self.assertLessEqual, 'bug', u'ant')
- self.assertRaises(self.failureException, self.assertLessEqual, u'bug', 'ant')
+ # Try bytes
+ self.assertGreater(b'bug', b'ant')
+ self.assertGreaterEqual(b'bug', b'ant')
+ self.assertGreaterEqual(b'ant', b'ant')
+ self.assertLess(b'ant', b'bug')
+ self.assertLessEqual(b'ant', b'bug')
+ self.assertLessEqual(b'ant', b'ant')
+ self.assertRaises(self.failureException, self.assertGreater, b'ant', b'bug')
+ self.assertRaises(self.failureException, self.assertGreater, b'ant', b'ant')
+ self.assertRaises(self.failureException, self.assertGreaterEqual, b'ant',
+ b'bug')
+ self.assertRaises(self.failureException, self.assertLess, b'bug', b'ant')
+ self.assertRaises(self.failureException, self.assertLess, b'ant', b'ant')
+ self.assertRaises(self.failureException, self.assertLessEqual, b'bug', b'ant')
def testAssertMultiLineEqual(self):
- sample_text = b"""\
+ sample_text = """\
http://www.python.org/doc/2.3/lib/module-unittest.html
test case
A test case is the smallest unit of testing. [...]
"""
- revised_sample_text = b"""\
+ revised_sample_text = """\
http://www.python.org/doc/2.4.1/lib/module-unittest.html
test case
A test case is the smallest unit of testing. [...] You may provide your
own implementation that does not subclass from TestCase, of course.
"""
- sample_text_error = b"""\
+ sample_text_error = """\
- http://www.python.org/doc/2.3/lib/module-unittest.html
? ^
+ http://www.python.org/doc/2.4.1/lib/module-unittest.html
@@ -916,21 +905,19 @@ test case
+ own implementation that does not subclass from TestCase, of course.
"""
self.maxDiff = None
- for type_changer in (lambda x: x, lambda x: x.decode('utf8')):
- try:
- self.assertMultiLineEqual(type_changer(sample_text),
- type_changer(revised_sample_text))
- except self.failureException, e:
- # need to remove the first line of the error message
- error = str(e).encode('utf8').split('\n', 1)[1]
+ try:
+ self.assertMultiLineEqual(sample_text, revised_sample_text)
+ except self.failureException as e:
+ # need to remove the first line of the error message
+ error = str(e).split('\n', 1)[1]
- # assertMultiLineEqual is hooked up as the default for
- # unicode strings - so we can't use it for this check
- self.assertTrue(sample_text_error == error)
+ # no fair testing ourself with ourself, and assertEqual is used for strings
+ # so can't use assertEqual either. Just use assertTrue.
+ self.assertTrue(sample_text_error == error)
def testAsertEqualSingleLine(self):
- sample_text = u"laden swallows fly slowly"
- revised_sample_text = u"unladen swallows fly quickly"
+ sample_text = "laden swallows fly slowly"
+ revised_sample_text = "unladen swallows fly quickly"
sample_text_error = """\
- laden swallows fly slowly
? ^^^^
@@ -949,54 +936,44 @@ test case
self.assertIsNotNone('DjZoPloGears on Rails')
self.assertRaises(self.failureException, self.assertIsNotNone, None)
- def testAssertRegexpMatches(self):
- self.assertRegexpMatches('asdfabasdf', r'ab+')
- self.assertRaises(self.failureException, self.assertRegexpMatches,
+ def testAssertRegex(self):
+ self.assertRegex('asdfabasdf', r'ab+')
+ self.assertRaises(self.failureException, self.assertRegex,
'saaas', r'aaaa')
- def testAssertRaisesRegexp(self):
+ def testAssertRaisesRegex(self):
class ExceptionMock(Exception):
pass
def Stub():
raise ExceptionMock('We expect')
- self.assertRaisesRegexp(ExceptionMock, re.compile('expect$'), Stub)
- self.assertRaisesRegexp(ExceptionMock, 'expect$', Stub)
- self.assertRaisesRegexp(ExceptionMock, u'expect$', Stub)
+ self.assertRaisesRegex(ExceptionMock, re.compile('expect$'), Stub)
+ self.assertRaisesRegex(ExceptionMock, 'expect$', Stub)
- def testAssertNotRaisesRegexp(self):
- self.assertRaisesRegexp(
- self.failureException, '^Exception not raised$',
- self.assertRaisesRegexp, Exception, re.compile('x'),
+ def testAssertNotRaisesRegex(self):
+ self.assertRaisesRegex(
+ self.failureException, '^Exception not raised by <lambda>$',
+ self.assertRaisesRegex, Exception, re.compile('x'),
lambda: None)
- self.assertRaisesRegexp(
- self.failureException, '^Exception not raised$',
- self.assertRaisesRegexp, Exception, 'x',
- lambda: None)
- self.assertRaisesRegexp(
- self.failureException, '^Exception not raised$',
- self.assertRaisesRegexp, Exception, u'x',
+ self.assertRaisesRegex(
+ self.failureException, '^Exception not raised by <lambda>$',
+ self.assertRaisesRegex, Exception, 'x',
lambda: None)
- def testAssertRaisesRegexpMismatch(self):
+ def testAssertRaisesRegexMismatch(self):
def Stub():
raise Exception('Unexpected')
- self.assertRaisesRegexp(
- self.failureException,
- r'"\^Expected\$" does not match "Unexpected"',
- self.assertRaisesRegexp, Exception, '^Expected$',
- Stub)
- self.assertRaisesRegexp(
+ self.assertRaisesRegex(
self.failureException,
r'"\^Expected\$" does not match "Unexpected"',
- self.assertRaisesRegexp, Exception, u'^Expected$',
+ self.assertRaisesRegex, Exception, '^Expected$',
Stub)
- self.assertRaisesRegexp(
+ self.assertRaisesRegex(
self.failureException,
r'"\^Expected\$" does not match "Unexpected"',
- self.assertRaisesRegexp, Exception,
+ self.assertRaisesRegex, Exception,
re.compile('^Expected$'), Stub)
def testAssertRaisesExcValue(self):
@@ -1014,33 +991,176 @@ test case
self.assertIsInstance(e, ExceptionMock)
self.assertEqual(e.args[0], v)
- def testSynonymAssertMethodNames(self):
- """Test undocumented method name synonyms.
-
- Please do not use these methods names in your own code.
-
- This test confirms their continued existence and functionality
- in order to avoid breaking existing code.
+ def testAssertWarnsCallable(self):
+ def _runtime_warn():
+ warnings.warn("foo", RuntimeWarning)
+ # Success when the right warning is triggered, even several times
+ self.assertWarns(RuntimeWarning, _runtime_warn)
+ self.assertWarns(RuntimeWarning, _runtime_warn)
+ # A tuple of warning classes is accepted
+ self.assertWarns((DeprecationWarning, RuntimeWarning), _runtime_warn)
+ # *args and **kwargs also work
+ self.assertWarns(RuntimeWarning,
+ warnings.warn, "foo", category=RuntimeWarning)
+ # Failure when no warning is triggered
+ with self.assertRaises(self.failureException):
+ self.assertWarns(RuntimeWarning, lambda: 0)
+ # Failure when another warning is triggered
+ with warnings.catch_warnings():
+ # Force default filter (in case tests are run with -We)
+ warnings.simplefilter("default", RuntimeWarning)
+ with self.assertRaises(self.failureException):
+ self.assertWarns(DeprecationWarning, _runtime_warn)
+ # Filters for other warnings are not modified
+ with warnings.catch_warnings():
+ warnings.simplefilter("error", RuntimeWarning)
+ with self.assertRaises(RuntimeWarning):
+ self.assertWarns(DeprecationWarning, _runtime_warn)
+
+ def testAssertWarnsContext(self):
+ # Believe it or not, it is preferrable to duplicate all tests above,
+ # to make sure the __warningregistry__ $@ is circumvented correctly.
+ def _runtime_warn():
+ warnings.warn("foo", RuntimeWarning)
+ _runtime_warn_lineno = inspect.getsourcelines(_runtime_warn)[1]
+ with self.assertWarns(RuntimeWarning) as cm:
+ _runtime_warn()
+ # A tuple of warning classes is accepted
+ with self.assertWarns((DeprecationWarning, RuntimeWarning)) as cm:
+ _runtime_warn()
+ # The context manager exposes various useful attributes
+ self.assertIsInstance(cm.warning, RuntimeWarning)
+ self.assertEqual(cm.warning.args[0], "foo")
+ self.assertIn("test_case.py", cm.filename)
+ self.assertEqual(cm.lineno, _runtime_warn_lineno + 1)
+ # Same with several warnings
+ with self.assertWarns(RuntimeWarning):
+ _runtime_warn()
+ _runtime_warn()
+ with self.assertWarns(RuntimeWarning):
+ warnings.warn("foo", category=RuntimeWarning)
+ # Failure when no warning is triggered
+ with self.assertRaises(self.failureException):
+ with self.assertWarns(RuntimeWarning):
+ pass
+ # Failure when another warning is triggered
+ with warnings.catch_warnings():
+ # Force default filter (in case tests are run with -We)
+ warnings.simplefilter("default", RuntimeWarning)
+ with self.assertRaises(self.failureException):
+ with self.assertWarns(DeprecationWarning):
+ _runtime_warn()
+ # Filters for other warnings are not modified
+ with warnings.catch_warnings():
+ warnings.simplefilter("error", RuntimeWarning)
+ with self.assertRaises(RuntimeWarning):
+ with self.assertWarns(DeprecationWarning):
+ _runtime_warn()
+
+ def testAssertWarnsRegexCallable(self):
+ def _runtime_warn(msg):
+ warnings.warn(msg, RuntimeWarning)
+ self.assertWarnsRegex(RuntimeWarning, "o+",
+ _runtime_warn, "foox")
+ # Failure when no warning is triggered
+ with self.assertRaises(self.failureException):
+ self.assertWarnsRegex(RuntimeWarning, "o+",
+ lambda: 0)
+ # Failure when another warning is triggered
+ with warnings.catch_warnings():
+ # Force default filter (in case tests are run with -We)
+ warnings.simplefilter("default", RuntimeWarning)
+ with self.assertRaises(self.failureException):
+ self.assertWarnsRegex(DeprecationWarning, "o+",
+ _runtime_warn, "foox")
+ # Failure when message doesn't match
+ with self.assertRaises(self.failureException):
+ self.assertWarnsRegex(RuntimeWarning, "o+",
+ _runtime_warn, "barz")
+ # A little trickier: we ask RuntimeWarnings to be raised, and then
+ # check for some of them. It is implementation-defined whether
+ # non-matching RuntimeWarnings are simply re-raised, or produce a
+ # failureException.
+ with warnings.catch_warnings():
+ warnings.simplefilter("error", RuntimeWarning)
+ with self.assertRaises((RuntimeWarning, self.failureException)):
+ self.assertWarnsRegex(RuntimeWarning, "o+",
+ _runtime_warn, "barz")
+
+ def testAssertWarnsRegexContext(self):
+ # Same as above, but with assertWarnsRegex as a context manager
+ def _runtime_warn(msg):
+ warnings.warn(msg, RuntimeWarning)
+ _runtime_warn_lineno = inspect.getsourcelines(_runtime_warn)[1]
+ with self.assertWarnsRegex(RuntimeWarning, "o+") as cm:
+ _runtime_warn("foox")
+ self.assertIsInstance(cm.warning, RuntimeWarning)
+ self.assertEqual(cm.warning.args[0], "foox")
+ self.assertIn("test_case.py", cm.filename)
+ self.assertEqual(cm.lineno, _runtime_warn_lineno + 1)
+ # Failure when no warning is triggered
+ with self.assertRaises(self.failureException):
+ with self.assertWarnsRegex(RuntimeWarning, "o+"):
+ pass
+ # Failure when another warning is triggered
+ with warnings.catch_warnings():
+ # Force default filter (in case tests are run with -We)
+ warnings.simplefilter("default", RuntimeWarning)
+ with self.assertRaises(self.failureException):
+ with self.assertWarnsRegex(DeprecationWarning, "o+"):
+ _runtime_warn("foox")
+ # Failure when message doesn't match
+ with self.assertRaises(self.failureException):
+ with self.assertWarnsRegex(RuntimeWarning, "o+"):
+ _runtime_warn("barz")
+ # A little trickier: we ask RuntimeWarnings to be raised, and then
+ # check for some of them. It is implementation-defined whether
+ # non-matching RuntimeWarnings are simply re-raised, or produce a
+ # failureException.
+ with warnings.catch_warnings():
+ warnings.simplefilter("error", RuntimeWarning)
+ with self.assertRaises((RuntimeWarning, self.failureException)):
+ with self.assertWarnsRegex(RuntimeWarning, "o+"):
+ _runtime_warn("barz")
+
+ def testDeprecatedMethodNames(self):
"""
- self.assertNotEquals(3, 5)
- self.assertEquals(3, 3)
- self.assertAlmostEquals(2.0, 2.0)
- self.assertNotAlmostEquals(3.0, 5.0)
- self.assert_(True)
-
- def testPendingDeprecationMethodNames(self):
- """Test fail* methods pending deprecation, they will warn in 3.2.
-
- Do not use these methods. They will go away in 3.3.
+ Test that the deprecated methods raise a DeprecationWarning. See #9424.
"""
- with test_support.check_warnings():
- self.failIfEqual(3, 5)
- self.failUnlessEqual(3, 3)
- self.failUnlessAlmostEqual(2.0, 2.0)
- self.failIfAlmostEqual(3.0, 5.0)
- self.failUnless(True)
- self.failUnlessRaises(TypeError, lambda _: 3.14 + u'spam')
- self.failIf(False)
+ old = (
+ (self.failIfEqual, (3, 5)),
+ (self.assertNotEquals, (3, 5)),
+ (self.failUnlessEqual, (3, 3)),
+ (self.assertEquals, (3, 3)),
+ (self.failUnlessAlmostEqual, (2.0, 2.0)),
+ (self.assertAlmostEquals, (2.0, 2.0)),
+ (self.failIfAlmostEqual, (3.0, 5.0)),
+ (self.assertNotAlmostEquals, (3.0, 5.0)),
+ (self.failUnless, (True,)),
+ (self.assert_, (True,)),
+ (self.failUnlessRaises, (TypeError, lambda _: 3.14 + 'spam')),
+ (self.failIf, (False,)),
+ (self.assertSameElements, ([1, 1, 2, 3], [1, 2, 3])),
+ (self.assertDictContainsSubset, (dict(a=1, b=2), dict(a=1, b=2, c=3))),
+ (self.assertRaisesRegexp, (KeyError, 'foo', lambda: {}['foo'])),
+ (self.assertRegexpMatches, ('bar', 'bar')),
+ )
+ for meth, args in old:
+ with self.assertWarns(DeprecationWarning):
+ meth(*args)
+
+ def testDeprecatedFailMethods(self):
+ """Test that the deprecated fail* methods get removed in 3.3"""
+ if sys.version_info[:2] < (3, 3):
+ return
+ deprecated_names = [
+ 'failIfEqual', 'failUnlessEqual', 'failUnlessAlmostEqual',
+ 'failIfAlmostEqual', 'failUnless', 'failUnlessRaises', 'failIf',
+ 'assertSameElements', 'assertDictContainsSubset',
+ ]
+ for deprecated_name in deprecated_names:
+ with self.assertRaises(AttributeError):
+ getattr(self, deprecated_name) # remove these in 3.3
def testDeepcopy(self):
# Issue: 5660
@@ -1053,6 +1173,23 @@ test case
# This shouldn't blow up
deepcopy(test)
+ def testPickle(self):
+ # Issue 10326
+
+ # Can't use TestCase classes defined in Test class as
+ # pickle does not work with inner classes
+ test = unittest.TestCase('run')
+ for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
+
+ # blew up prior to fix
+ pickled_test = pickle.dumps(test, protocol=protocol)
+ unpickled_test = pickle.loads(pickled_test)
+ self.assertEqual(test, unpickled_test)
+
+ # exercise the TestCase instance in a way that will invoke
+ # the type equality lookup mechanism
+ unpickled_test.assertEqual(set(), set())
+
def testKeyboardInterrupt(self):
def _raise(self=None):
raise KeyboardInterrupt
@@ -1078,6 +1215,33 @@ test case
with self.assertRaises(KeyboardInterrupt):
klass('test_something').run()
+ def testSkippingEverywhere(self):
+ def _skip(self=None):
+ raise unittest.SkipTest('some reason')
+ def nothing(self):
+ pass
+
+ class Test1(unittest.TestCase):
+ test_something = _skip
+
+ class Test2(unittest.TestCase):
+ setUp = _skip
+ test_something = nothing
+
+ class Test3(unittest.TestCase):
+ test_something = nothing
+ tearDown = _skip
+
+ class Test4(unittest.TestCase):
+ def test_something(self):
+ self.addCleanup(_skip)
+
+ for klass in (Test1, Test2, Test3, Test4):
+ result = unittest.TestResult()
+ klass('test_something').run(result)
+ self.assertEqual(len(result.skipped), 1)
+ self.assertEqual(result.testsRun, 1)
+
def testSystemExit(self):
def _raise(self=None):
raise SystemExit
@@ -1104,21 +1268,3 @@ test case
klass('test_something').run(result)
self.assertEqual(len(result.errors), 1)
self.assertEqual(result.testsRun, 1)
-
- def testPickle(self):
- # Issue 10326
-
- # Can't use TestCase classes defined in Test class as
- # pickle does not work with inner classes
- test = unittest.TestCase('run')
- for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
-
- # blew up prior to fix
- pickled_test = pickle.dumps(test, protocol=protocol)
-
- unpickled_test = pickle.loads(pickled_test)
- self.assertEqual(test, unpickled_test)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/Lib/unittest/test/test_discovery.py b/Lib/unittest/test/test_discovery.py
index 1155de116f9..e688f8e35ac 100644
--- a/Lib/unittest/test/test_discovery.py
+++ b/Lib/unittest/test/test_discovery.py
@@ -5,12 +5,23 @@ import sys
import unittest
+class TestableTestProgram(unittest.TestProgram):
+ module = '__main__'
+ exit = True
+ defaultTest = failfast = catchbreak = buffer = None
+ verbosity = 1
+ progName = ''
+ testRunner = testLoader = None
+
+ def __init__(self):
+ pass
+
+
class TestDiscovery(unittest.TestCase):
# Heavily mocked tests so I can avoid hitting the filesystem
def test_get_name_from_path(self):
loader = unittest.TestLoader()
-
loader._top_level_dir = '/foo'
name = loader._get_name_from_path('/foo/bar/baz.py')
self.assertEqual(name, 'bar.baz')
@@ -105,9 +116,6 @@ class TestDiscovery(unittest.TestCase):
def __eq__(self, other):
return self.path == other.path
- # Silence py3k warning
- __hash__ = None
-
loader._get_module_from_name = lambda name: Module(name)
def loadTestsFromModule(module, use_load_tests):
if use_load_tests:
@@ -199,8 +207,7 @@ class TestDiscovery(unittest.TestCase):
test.test_this_does_not_exist()
def test_command_line_handling_parseArgs(self):
- # Haha - take that uninstantiable class
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
args = []
def do_discovery(argv):
@@ -212,13 +219,39 @@ class TestDiscovery(unittest.TestCase):
program.parseArgs(['something', 'discover', 'foo', 'bar'])
self.assertEqual(args, ['foo', 'bar'])
+ def test_command_line_handling_discover_by_default(self):
+ program = TestableTestProgram()
+ program.module = None
+
+ self.called = False
+ def do_discovery(argv):
+ self.called = True
+ self.assertEqual(argv, [])
+ program._do_discovery = do_discovery
+ program.parseArgs(['something'])
+ self.assertTrue(self.called)
+
+ def test_command_line_handling_discover_by_default_with_options(self):
+ program = TestableTestProgram()
+ program.module = None
+
+ args = ['something', '-v', '-b', '-v', '-c', '-f']
+ self.called = False
+ def do_discovery(argv):
+ self.called = True
+ self.assertEqual(argv, args[1:])
+ program._do_discovery = do_discovery
+ program.parseArgs(args)
+ self.assertTrue(self.called)
+
+
def test_command_line_handling_do_discovery_too_many_arguments(self):
class Stop(Exception):
pass
def usageExit():
raise Stop
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
program.usageExit = usageExit
with self.assertRaises(Stop):
@@ -227,7 +260,7 @@ class TestDiscovery(unittest.TestCase):
def test_command_line_handling_do_discovery_calls_loader(self):
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
class Loader(object):
args = []
@@ -241,49 +274,49 @@ class TestDiscovery(unittest.TestCase):
self.assertEqual(Loader.args, [('.', 'test*.py', None)])
Loader.args = []
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
program._do_discovery(['--verbose'], Loader=Loader)
self.assertEqual(program.test, 'tests')
self.assertEqual(Loader.args, [('.', 'test*.py', None)])
Loader.args = []
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
program._do_discovery([], Loader=Loader)
self.assertEqual(program.test, 'tests')
self.assertEqual(Loader.args, [('.', 'test*.py', None)])
Loader.args = []
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
program._do_discovery(['fish'], Loader=Loader)
self.assertEqual(program.test, 'tests')
self.assertEqual(Loader.args, [('fish', 'test*.py', None)])
Loader.args = []
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
program._do_discovery(['fish', 'eggs'], Loader=Loader)
self.assertEqual(program.test, 'tests')
self.assertEqual(Loader.args, [('fish', 'eggs', None)])
Loader.args = []
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
program._do_discovery(['fish', 'eggs', 'ham'], Loader=Loader)
self.assertEqual(program.test, 'tests')
self.assertEqual(Loader.args, [('fish', 'eggs', 'ham')])
Loader.args = []
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
program._do_discovery(['-s', 'fish'], Loader=Loader)
self.assertEqual(program.test, 'tests')
self.assertEqual(Loader.args, [('fish', 'test*.py', None)])
Loader.args = []
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
program._do_discovery(['-t', 'fish'], Loader=Loader)
self.assertEqual(program.test, 'tests')
self.assertEqual(Loader.args, [('.', 'test*.py', 'fish')])
Loader.args = []
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
program._do_discovery(['-p', 'fish'], Loader=Loader)
self.assertEqual(program.test, 'tests')
self.assertEqual(Loader.args, [('.', 'fish', None)])
@@ -291,7 +324,7 @@ class TestDiscovery(unittest.TestCase):
self.assertFalse(program.catchbreak)
Loader.args = []
- program = object.__new__(unittest.TestProgram)
+ program = TestableTestProgram()
program._do_discovery(['-p', 'eggs', '-s', 'fish', '-v', '-f', '-c'],
Loader=Loader)
self.assertEqual(program.test, 'tests')
@@ -334,7 +367,7 @@ class TestDiscovery(unittest.TestCase):
expected_dir = os.path.abspath('foo')
msg = re.escape(r"'foo' module incorrectly imported from %r. Expected %r. "
"Is this module globally installed?" % (mod_dir, expected_dir))
- self.assertRaisesRegexp(
+ self.assertRaisesRegex(
ImportError, '^%s$' % msg, loader.discover,
start_dir='foo', pattern='foo.py'
)
diff --git a/Lib/unittest/test/test_functiontestcase.py b/Lib/unittest/test/test_functiontestcase.py
index 63dd8781509..9ce5ee3556e 100644
--- a/Lib/unittest/test/test_functiontestcase.py
+++ b/Lib/unittest/test/test_functiontestcase.py
@@ -58,8 +58,8 @@ class Test_FunctionTestCase(unittest.TestCase):
def tearDown():
events.append('tearDown')
- expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown',
- 'stopTest']
+ expected = ['startTest', 'setUp', 'test', 'tearDown',
+ 'addError', 'stopTest']
unittest.FunctionTestCase(test, setUp, tearDown).run(result)
self.assertEqual(events, expected)
@@ -84,8 +84,8 @@ class Test_FunctionTestCase(unittest.TestCase):
def tearDown():
events.append('tearDown')
- expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown',
- 'stopTest']
+ expected = ['startTest', 'setUp', 'test', 'tearDown',
+ 'addFailure', 'stopTest']
unittest.FunctionTestCase(test, setUp, tearDown).run(result)
self.assertEqual(events, expected)
@@ -124,7 +124,7 @@ class Test_FunctionTestCase(unittest.TestCase):
def test_id(self):
test = unittest.FunctionTestCase(lambda: None)
- self.assertIsInstance(test.id(), basestring)
+ self.assertIsInstance(test.id(), str)
# "Returns a one-line description of the test, or None if no description
# has been provided. The default implementation of this method returns
@@ -142,7 +142,3 @@ class Test_FunctionTestCase(unittest.TestCase):
test = unittest.FunctionTestCase(lambda: None, description=desc)
self.assertEqual(test.shortDescription(), "this tests foo")
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/Lib/unittest/test/test_loader.py b/Lib/unittest/test/test_loader.py
index 3544a20f7cf..f7e31a57f1b 100644
--- a/Lib/unittest/test/test_loader.py
+++ b/Lib/unittest/test/test_loader.py
@@ -186,7 +186,7 @@ class Test_TestLoader(unittest.TestCase):
self.assertEqual(suite.countTestCases(), 1)
test = list(suite)[0]
- self.assertRaisesRegexp(TypeError, "some failure", test.m)
+ self.assertRaisesRegex(TypeError, "some failure", test.m)
################################################################
### /Tests for TestLoader.loadTestsFromModule()
@@ -205,7 +205,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromName('')
- except ValueError, e:
+ except ValueError as e:
self.assertEqual(str(e), "Empty module name")
else:
self.fail("TestLoader.loadTestsFromName failed to raise ValueError")
@@ -238,7 +238,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromName('sdasfasfasdf')
- except ImportError, e:
+ except ImportError as e:
self.assertEqual(str(e), "No module named sdasfasfasdf")
else:
self.fail("TestLoader.loadTestsFromName failed to raise ImportError")
@@ -254,7 +254,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromName('unittest.sdasfasfasdf')
- except AttributeError, e:
+ except AttributeError as e:
self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
else:
self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
@@ -271,7 +271,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromName('sdasfasfasdf', unittest)
- except AttributeError, e:
+ except AttributeError as e:
self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
else:
self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
@@ -292,7 +292,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromName('', unittest)
- except AttributeError:
+ except AttributeError as e:
pass
else:
self.fail("Failed to raise AttributeError")
@@ -425,7 +425,7 @@ class Test_TestLoader(unittest.TestCase):
loader = unittest.TestLoader()
try:
loader.loadTestsFromName('testcase_1.testfoo', m)
- except AttributeError, e:
+ except AttributeError as e:
self.assertEqual(str(e), "type object 'MyTestCase' has no attribute 'testfoo'")
else:
self.fail("Failed to raise AttributeError")
@@ -512,7 +512,7 @@ class Test_TestLoader(unittest.TestCase):
loader = unittest.TestLoader()
try:
- loader.loadTestsFromName('return_wrong', m)
+ suite = loader.loadTestsFromName('return_wrong', m)
except TypeError:
pass
else:
@@ -583,7 +583,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromNames([''])
- except ValueError, e:
+ except ValueError as e:
self.assertEqual(str(e), "Empty module name")
else:
self.fail("TestLoader.loadTestsFromNames failed to raise ValueError")
@@ -618,7 +618,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromNames(['sdasfasfasdf'])
- except ImportError, e:
+ except ImportError as e:
self.assertEqual(str(e), "No module named sdasfasfasdf")
else:
self.fail("TestLoader.loadTestsFromNames failed to raise ImportError")
@@ -634,7 +634,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromNames(['unittest.sdasfasfasdf', 'unittest'])
- except AttributeError, e:
+ except AttributeError as e:
self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
else:
self.fail("TestLoader.loadTestsFromNames failed to raise AttributeError")
@@ -653,7 +653,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromNames(['sdasfasfasdf'], unittest)
- except AttributeError, e:
+ except AttributeError as e:
self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
else:
self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
@@ -672,7 +672,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromNames(['TestCase', 'sdasfasfasdf'], unittest)
- except AttributeError, e:
+ except AttributeError as e:
self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
else:
self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
@@ -821,7 +821,7 @@ class Test_TestLoader(unittest.TestCase):
loader = unittest.TestLoader()
try:
loader.loadTestsFromNames(['testcase_1.testfoo'], m)
- except AttributeError, e:
+ except AttributeError as e:
self.assertEqual(str(e), "type object 'MyTestCase' has no attribute 'testfoo'")
else:
self.fail("Failed to raise AttributeError")
@@ -895,7 +895,7 @@ class Test_TestLoader(unittest.TestCase):
loader = unittest.TestLoader()
try:
- loader.loadTestsFromNames(['return_wrong'], m)
+ suite = loader.loadTestsFromNames(['return_wrong'], m)
except TypeError:
pass
else:
@@ -1093,7 +1093,7 @@ class Test_TestLoader(unittest.TestCase):
# "The default value is 'test'"
def test_testMethodPrefix__default_value(self):
loader = unittest.TestLoader()
- self.assertTrue(loader.testMethodPrefix == 'test')
+ self.assertEqual(loader.testMethodPrefix, 'test')
################################################################
### /Tests for TestLoader.testMethodPrefix
@@ -1105,7 +1105,7 @@ class Test_TestLoader(unittest.TestCase):
# getTestCaseNames() and all the loadTestsFromX() methods"
def test_sortTestMethodsUsing__loadTestsFromTestCase(self):
def reversed_cmp(x, y):
- return -cmp(x, y)
+ return -((x > y) - (x < y))
class Foo(unittest.TestCase):
def test_1(self): pass
@@ -1121,7 +1121,7 @@ class Test_TestLoader(unittest.TestCase):
# getTestCaseNames() and all the loadTestsFromX() methods"
def test_sortTestMethodsUsing__loadTestsFromModule(self):
def reversed_cmp(x, y):
- return -cmp(x, y)
+ return -((x > y) - (x < y))
m = types.ModuleType('m')
class Foo(unittest.TestCase):
@@ -1139,7 +1139,7 @@ class Test_TestLoader(unittest.TestCase):
# getTestCaseNames() and all the loadTestsFromX() methods"
def test_sortTestMethodsUsing__loadTestsFromName(self):
def reversed_cmp(x, y):
- return -cmp(x, y)
+ return -((x > y) - (x < y))
m = types.ModuleType('m')
class Foo(unittest.TestCase):
@@ -1157,7 +1157,7 @@ class Test_TestLoader(unittest.TestCase):
# getTestCaseNames() and all the loadTestsFromX() methods"
def test_sortTestMethodsUsing__loadTestsFromNames(self):
def reversed_cmp(x, y):
- return -cmp(x, y)
+ return -((x > y) - (x < y))
m = types.ModuleType('m')
class Foo(unittest.TestCase):
@@ -1177,7 +1177,7 @@ class Test_TestLoader(unittest.TestCase):
# Does it actually affect getTestCaseNames()?
def test_sortTestMethodsUsing__getTestCaseNames(self):
def reversed_cmp(x, y):
- return -cmp(x, y)
+ return -((x > y) - (x < y))
class Foo(unittest.TestCase):
def test_1(self): pass
@@ -1190,9 +1190,19 @@ class Test_TestLoader(unittest.TestCase):
self.assertEqual(loader.getTestCaseNames(Foo), test_names)
# "The default value is the built-in cmp() function"
+ # Since cmp is now defunct, we simply verify that the results
+ # occur in the same order as they would with the default sort.
def test_sortTestMethodsUsing__default_value(self):
loader = unittest.TestLoader()
- self.assertTrue(loader.sortTestMethodsUsing is cmp)
+
+ class Foo(unittest.TestCase):
+ def test_2(self): pass
+ def test_3(self): pass
+ def test_1(self): pass
+
+ test_names = ['test_2', 'test_3', 'test_1']
+ self.assertEqual(loader.getTestCaseNames(Foo), sorted(test_names))
+
# "it can be set to None to disable the sort."
#
@@ -1280,7 +1290,3 @@ class Test_TestLoader(unittest.TestCase):
def test_suiteClass__default_value(self):
loader = unittest.TestLoader()
self.assertTrue(loader.suiteClass is unittest.TestSuite)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/Lib/unittest/test/test_program.py b/Lib/unittest/test/test_program.py
index 45d90975e7d..d5d0f5a71c1 100644
--- a/Lib/unittest/test/test_program.py
+++ b/Lib/unittest/test/test_program.py
@@ -1,4 +1,4 @@
-from cStringIO import StringIO
+import io
import os
import sys
@@ -68,7 +68,7 @@ class Test_TestProgram(unittest.TestCase):
def test_NonExit(self):
program = unittest.main(exit=False,
argv=["foobar"],
- testRunner=unittest.TextTestRunner(stream=StringIO()),
+ testRunner=unittest.TextTestRunner(stream=io.StringIO()),
testLoader=self.FooBarLoader())
self.assertTrue(hasattr(program, 'result'))
@@ -78,7 +78,7 @@ class Test_TestProgram(unittest.TestCase):
SystemExit,
unittest.main,
argv=["foobar"],
- testRunner=unittest.TextTestRunner(stream=StringIO()),
+ testRunner=unittest.TextTestRunner(stream=io.StringIO()),
exit=True,
testLoader=self.FooBarLoader())
@@ -88,7 +88,7 @@ class Test_TestProgram(unittest.TestCase):
SystemExit,
unittest.main,
argv=["foobar"],
- testRunner=unittest.TextTestRunner(stream=StringIO()),
+ testRunner=unittest.TextTestRunner(stream=io.StringIO()),
testLoader=self.FooBarLoader())
@@ -99,6 +99,7 @@ class InitialisableProgram(unittest.TestProgram):
defaultTest = None
testRunner = None
testLoader = unittest.defaultTestLoader
+ module = '__main__'
progName = 'test'
test = 'test'
def __init__(self, *args):
@@ -182,6 +183,27 @@ class TestCommandLineArgs(unittest.TestCase):
program.parseArgs([None, opt])
self.assertEqual(getattr(program, attr), not_none)
+ def testWarning(self):
+ """Test the warnings argument"""
+ # see #10535
+ class FakeTP(unittest.TestProgram):
+ def parseArgs(self, *args, **kw): pass
+ def runTests(self, *args, **kw): pass
+ warnoptions = sys.warnoptions[:]
+ try:
+ sys.warnoptions[:] = []
+ # no warn options, no arg -> default
+ self.assertEqual(FakeTP().warnings, 'default')
+ # no warn options, w/ arg -> arg value
+ self.assertEqual(FakeTP(warnings='ignore').warnings, 'ignore')
+ sys.warnoptions[:] = ['somevalue']
+ # warn options, no arg -> None
+ # warn options, w/ arg -> arg value
+ self.assertEqual(FakeTP().warnings, None)
+ self.assertEqual(FakeTP(warnings='ignore').warnings, 'ignore')
+ finally:
+ sys.warnoptions[:] = warnoptions
+
def testRunTestsRunnerClass(self):
program = self.program
@@ -189,12 +211,14 @@ class TestCommandLineArgs(unittest.TestCase):
program.verbosity = 'verbosity'
program.failfast = 'failfast'
program.buffer = 'buffer'
+ program.warnings = 'warnings'
program.runTests()
self.assertEqual(FakeRunner.initArgs, {'verbosity': 'verbosity',
'failfast': 'failfast',
- 'buffer': 'buffer'})
+ 'buffer': 'buffer',
+ 'warnings': 'warnings'})
self.assertEqual(FakeRunner.test, 'test')
self.assertIs(program.result, RESULT)
@@ -224,7 +248,7 @@ class TestCommandLineArgs(unittest.TestCase):
program.runTests()
- # If initializing raises a type error it should be retried
+ # If initialising raises a type error it should be retried
# without the new keyword arguments
self.assertEqual(FakeRunner.initArgs, {})
self.assertEqual(FakeRunner.test, 'test')
@@ -250,6 +274,85 @@ class TestCommandLineArgs(unittest.TestCase):
program.runTests()
self.assertTrue(self.installed)
+ def _patch_isfile(self, names, exists=True):
+ def isfile(path):
+ return path in names
+ original = os.path.isfile
+ os.path.isfile = isfile
+ def restore():
+ os.path.isfile = original
+ self.addCleanup(restore)
+
+
+ def testParseArgsFileNames(self):
+ # running tests with filenames instead of module names
+ program = self.program
+ argv = ['progname', 'foo.py', 'bar.Py', 'baz.PY', 'wing.txt']
+ self._patch_isfile(argv)
+
+ program.createTests = lambda: None
+ program.parseArgs(argv)
+
+ # note that 'wing.txt' is not a Python file so the name should
+ # *not* be converted to a module name
+ expected = ['foo', 'bar', 'baz', 'wing.txt']
+ self.assertEqual(program.testNames, expected)
+
+
+ def testParseArgsFilePaths(self):
+ program = self.program
+ argv = ['progname', 'foo/bar/baz.py', 'green\\red.py']
+ self._patch_isfile(argv)
+
+ program.createTests = lambda: None
+ program.parseArgs(argv)
+
+ expected = ['foo.bar.baz', 'green.red']
+ self.assertEqual(program.testNames, expected)
+
+
+ def testParseArgsNonExistentFiles(self):
+ program = self.program
+ argv = ['progname', 'foo/bar/baz.py', 'green\\red.py']
+ self._patch_isfile([])
+
+ program.createTests = lambda: None
+ program.parseArgs(argv)
+
+ self.assertEqual(program.testNames, argv[1:])
+
+ def testParseArgsAbsolutePathsThatCanBeConverted(self):
+ cur_dir = os.getcwd()
+ program = self.program
+ def _join(name):
+ return os.path.join(cur_dir, name)
+ argv = ['progname', _join('foo/bar/baz.py'), _join('green\\red.py')]
+ self._patch_isfile(argv)
+
+ program.createTests = lambda: None
+ program.parseArgs(argv)
+
+ expected = ['foo.bar.baz', 'green.red']
+ self.assertEqual(program.testNames, expected)
+
+ def testParseArgsAbsolutePathsThatCannotBeConverted(self):
+ program = self.program
+ # even on Windows '/...' is considered absolute by os.path.abspath
+ argv = ['progname', '/foo/bar/baz.py', '/green/red.py']
+ self._patch_isfile(argv)
+
+ program.createTests = lambda: None
+ program.parseArgs(argv)
+
+ self.assertEqual(program.testNames, argv[1:])
+
+ # it may be better to use platform specific functions to normalise paths
+ # rather than accepting '.PY' and '\' as file seprator on Linux / Mac
+ # it would also be better to check that a filename is a valid module
+ # identifier (we have a regex for this in loader.py)
+ # for invalid filenames should we raise a useful error rather than
+ # leaving the current error message (import of filename fails) in place?
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/unittest/test/test_result.py b/Lib/unittest/test/test_result.py
index eb68c1d01c2..1c58e61bb2b 100644
--- a/Lib/unittest/test/test_result.py
+++ b/Lib/unittest/test/test_result.py
@@ -1,7 +1,8 @@
+import io
import sys
import textwrap
-from StringIO import StringIO
-from test import test_support
+
+from test import support
import traceback
import unittest
@@ -28,7 +29,6 @@ class Test_TestResult(unittest.TestCase):
self.assertIsNone(result._stdout_buffer)
self.assertIsNone(result._stderr_buffer)
-
# "This method can be called to signal that the set of tests being
# run should be aborted by setting the TestResult's shouldStop
# attribute to True."
@@ -289,10 +289,10 @@ class Test_TestResult(unittest.TestCase):
self.assertTrue(result.shouldStop)
def testFailFastSetByRunner(self):
- runner = unittest.TextTestRunner(stream=StringIO(), failfast=True)
+ runner = unittest.TextTestRunner(stream=io.StringIO(), failfast=True)
def test(result):
self.assertTrue(result.failfast)
- runner.run(test)
+ result = runner.run(test)
classDict = dict(unittest.TestResult.__dict__)
@@ -313,8 +313,8 @@ OldResult = type('OldResult', (object,), classDict)
class Test_OldTestResult(unittest.TestCase):
def assertOldResultWarning(self, test, failures):
- with test_support.check_warnings(("TestResult has no add.+ method,",
- RuntimeWarning)):
+ with support.check_warnings(("TestResult has no add.+ method,",
+ RuntimeWarning)):
result = OldResult()
test.run(result)
self.assertEqual(len(result.failures), failures)
@@ -356,7 +356,7 @@ class Test_OldTestResult(unittest.TestCase):
def testFoo(self):
pass
runner = unittest.TextTestRunner(resultclass=OldResult,
- stream=StringIO())
+ stream=io.StringIO())
# This will raise an exception if TextTestRunner can't handle old
# test result objects
runner.run(Test('testFoo'))
@@ -412,18 +412,18 @@ class TestOutputBuffering(unittest.TestCase):
self.assertIsNot(real_out, sys.stdout)
self.assertIsNot(real_err, sys.stderr)
- self.assertIsInstance(sys.stdout, StringIO)
- self.assertIsInstance(sys.stderr, StringIO)
+ self.assertIsInstance(sys.stdout, io.StringIO)
+ self.assertIsInstance(sys.stderr, io.StringIO)
self.assertIsNot(sys.stdout, sys.stderr)
out_stream = sys.stdout
err_stream = sys.stderr
- result._original_stdout = StringIO()
- result._original_stderr = StringIO()
+ result._original_stdout = io.StringIO()
+ result._original_stderr = io.StringIO()
- print 'foo'
- print >> sys.stderr, 'bar'
+ print('foo')
+ print('bar', file=sys.stderr)
self.assertEqual(out_stream.getvalue(), 'foo\n')
self.assertEqual(err_stream.getvalue(), 'bar\n')
@@ -463,12 +463,12 @@ class TestOutputBuffering(unittest.TestCase):
result = self.getStartedResult()
buffered_out = sys.stdout
buffered_err = sys.stderr
- result._original_stdout = StringIO()
- result._original_stderr = StringIO()
+ result._original_stdout = io.StringIO()
+ result._original_stderr = io.StringIO()
- print >> sys.stdout, 'foo'
+ print('foo', file=sys.stdout)
if include_error:
- print >> sys.stderr, 'bar'
+ print('bar', file=sys.stderr)
addFunction = getattr(result, add_attr)
@@ -489,6 +489,7 @@ class TestOutputBuffering(unittest.TestCase):
Stderr:
bar
""")
+
expectedFullMessage = 'A traceback%s%s' % (expectedOutMessage, expectedErrMessage)
self.assertIs(test, self)
@@ -503,7 +504,7 @@ class TestOutputBuffering(unittest.TestCase):
class Foo(unittest.TestCase):
@classmethod
def setUpClass(cls):
- 1//0
+ 1/0
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
@@ -517,7 +518,7 @@ class TestOutputBuffering(unittest.TestCase):
class Foo(unittest.TestCase):
@classmethod
def tearDownClass(cls):
- 1//0
+ 1/0
def test_foo(self):
pass
suite = unittest.TestSuite([Foo('test_foo')])
@@ -534,7 +535,7 @@ class TestOutputBuffering(unittest.TestCase):
class Module(object):
@staticmethod
def setUpModule():
- 1//0
+ 1/0
Foo.__module__ = 'Module'
sys.modules['Module'] = Module
@@ -553,7 +554,7 @@ class TestOutputBuffering(unittest.TestCase):
class Module(object):
@staticmethod
def tearDownModule():
- 1//0
+ 1/0
Foo.__module__ = 'Module'
sys.modules['Module'] = Module
diff --git a/Lib/unittest/test/test_runner.py b/Lib/unittest/test/test_runner.py
index d1cefae4c17..aed1e76940a 100644
--- a/Lib/unittest/test/test_runner.py
+++ b/Lib/unittest/test/test_runner.py
@@ -1,7 +1,10 @@
-import unittest
-
-from cStringIO import StringIO
+import io
+import os
+import sys
import pickle
+import subprocess
+
+import unittest
from .support import LoggingResult, ResultWithNoStartTestRunStopTestRun
@@ -31,25 +34,20 @@ class TestCleanUp(unittest.TestCase):
[(cleanup1, (1, 2, 3), dict(four='hello', five='goodbye')),
(cleanup2, (), {})])
- result = test.doCleanups()
- self.assertTrue(result)
-
- self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3),
- dict(four='hello', five='goodbye'))])
+ self.assertTrue(test.doCleanups())
+ self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))])
def testCleanUpWithErrors(self):
class TestableTest(unittest.TestCase):
def testNothing(self):
pass
- class MockResult(object):
+ class MockOutcome(object):
+ success = True
errors = []
- def addError(self, test, exc_info):
- self.errors.append((test, exc_info))
- result = MockResult()
test = TestableTest('testNothing')
- test._resultForDoCleanups = result
+ test._outcomeForDoCleanups = MockOutcome
exc1 = Exception('foo')
exc2 = Exception('bar')
@@ -63,10 +61,11 @@ class TestCleanUp(unittest.TestCase):
test.addCleanup(cleanup2)
self.assertFalse(test.doCleanups())
+ self.assertFalse(MockOutcome.success)
- (test1, (Type1, instance1, _)), (test2, (Type2, instance2, _)) = reversed(MockResult.errors)
- self.assertEqual((test1, Type1, instance1), (test, Exception, exc1))
- self.assertEqual((test2, Type2, instance2), (test, Exception, exc2))
+ (Type1, instance1, _), (Type2, instance2, _) = reversed(MockOutcome.errors)
+ self.assertEqual((Type1, instance1), (Exception, exc1))
+ self.assertEqual((Type2, instance2), (Exception, exc2))
def testCleanupInRun(self):
blowUp = False
@@ -145,6 +144,7 @@ class Test_TextTestRunner(unittest.TestCase):
self.assertFalse(runner.failfast)
self.assertFalse(runner.buffer)
self.assertEqual(runner.verbosity, 1)
+ self.assertEqual(runner.warnings, None)
self.assertTrue(runner.descriptions)
self.assertEqual(runner.resultclass, unittest.TextTestResult)
@@ -159,7 +159,7 @@ class Test_TextTestRunner(unittest.TestCase):
# This used to raise an exception due to TextTestResult not passing
# on arguments in its __init__ super call
- ATextResult(None, None, None)
+ ATextResult(None, None, 1)
def testBufferAndFailfast(self):
@@ -167,7 +167,7 @@ class Test_TextTestRunner(unittest.TestCase):
def testFoo(self):
pass
result = unittest.TestResult()
- runner = unittest.TextTestRunner(stream=StringIO(), failfast=True,
+ runner = unittest.TextTestRunner(stream=io.StringIO(), failfast=True,
buffer=True)
# Use our result object
runner._makeResult = lambda: result
@@ -186,7 +186,7 @@ class Test_TextTestRunner(unittest.TestCase):
self.addCleanup(cleanup)
result = unittest.TestResult()
- runner = unittest.TextTestRunner(stream=StringIO())
+ runner = unittest.TextTestRunner(stream=io.StringIO())
# Use our result object
runner._makeResult = lambda: result
@@ -207,7 +207,7 @@ class Test_TextTestRunner(unittest.TestCase):
class Runner(unittest.TextTestRunner):
def __init__(self):
- super(Runner, self).__init__(StringIO())
+ super(Runner, self).__init__(io.StringIO())
def _makeResult(self):
return OldTextResult()
@@ -223,7 +223,7 @@ class Test_TextTestRunner(unittest.TestCase):
class LoggingRunner(unittest.TextTestRunner):
def __init__(self, events):
- super(LoggingRunner, self).__init__(StringIO())
+ super(LoggingRunner, self).__init__(io.StringIO())
self._events = events
def _makeResult(self):
@@ -238,12 +238,10 @@ class Test_TextTestRunner(unittest.TestCase):
def test_pickle_unpickle(self):
# Issue #7197: a TextTestRunner should be (un)pickleable. This is
# required by test_multiprocessing under Windows (in verbose mode).
- from StringIO import StringIO as PickleableIO
- # cStringIO objects are not pickleable, but StringIO objects are.
- stream = PickleableIO("foo")
+ stream = io.StringIO("foo")
runner = unittest.TextTestRunner(stream)
- for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
- s = pickle.dumps(runner, protocol=protocol)
+ for protocol in range(2, pickle.HIGHEST_PROTOCOL + 1):
+ s = pickle.dumps(runner, protocol)
obj = pickle.loads(s)
# StringIO objects never compare equal, a cheap test instead.
self.assertEqual(obj.stream.getvalue(), stream.getvalue())
@@ -261,6 +259,73 @@ class Test_TextTestRunner(unittest.TestCase):
expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY)
self.assertEqual(runner._makeResult(), expectedresult)
-
-if __name__ == '__main__':
- unittest.main()
+ def test_warnings(self):
+ """
+ Check that warnings argument of TextTestRunner correctly affects the
+ behavior of the warnings.
+ """
+ # see #10535 and the _test_warnings file for more information
+
+ def get_parse_out_err(p):
+ return [b.splitlines() for b in p.communicate()]
+ opts = dict(stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ cwd=os.path.dirname(__file__))
+ ae_msg = b'Please use assertEqual instead.'
+ at_msg = b'Please use assertTrue instead.'
+
+ # no args -> all the warnings are printed, unittest warnings only once
+ p = subprocess.Popen([sys.executable, '_test_warnings.py'], **opts)
+ out, err = get_parse_out_err(p)
+ self.assertIn(b'OK', err)
+ # check that the total number of warnings in the output is correct
+ self.assertEqual(len(out), 12)
+ # check that the numbers of the different kind of warnings is correct
+ for msg in [b'dw', b'iw', b'uw']:
+ self.assertEqual(out.count(msg), 3)
+ for msg in [ae_msg, at_msg, b'rw']:
+ self.assertEqual(out.count(msg), 1)
+
+ args_list = (
+ # passing 'ignore' as warnings arg -> no warnings
+ [sys.executable, '_test_warnings.py', 'ignore'],
+ # -W doesn't affect the result if the arg is passed
+ [sys.executable, '-Wa', '_test_warnings.py', 'ignore'],
+ # -W affects the result if the arg is not passed
+ [sys.executable, '-Wi', '_test_warnings.py']
+ )
+ # in all these cases no warnings are printed
+ for args in args_list:
+ p = subprocess.Popen(args, **opts)
+ out, err = get_parse_out_err(p)
+ self.assertIn(b'OK', err)
+ self.assertEqual(len(out), 0)
+
+
+ # passing 'always' as warnings arg -> all the warnings printed,
+ # unittest warnings only once
+ p = subprocess.Popen([sys.executable, '_test_warnings.py', 'always'],
+ **opts)
+ out, err = get_parse_out_err(p)
+ self.assertIn(b'OK', err)
+ self.assertEqual(len(out), 14)
+ for msg in [b'dw', b'iw', b'uw', b'rw']:
+ self.assertEqual(out.count(msg), 3)
+ for msg in [ae_msg, at_msg]:
+ self.assertEqual(out.count(msg), 1)
+
+ def testStdErrLookedUpAtInstantiationTime(self):
+ # see issue 10786
+ old_stderr = sys.stderr
+ f = io.StringIO()
+ sys.stderr = f
+ try:
+ runner = unittest.TextTestRunner()
+ self.assertTrue(runner.stream.stream is f)
+ finally:
+ sys.stderr = old_stderr
+
+ def testSpecifiedStreamUsed(self):
+ # see issue 10786
+ f = io.StringIO()
+ runner = unittest.TextTestRunner(f)
+ self.assertTrue(runner.stream.stream is f)
diff --git a/Lib/unittest/test/test_setups.py b/Lib/unittest/test/test_setups.py
index 9456819ea16..b8d5aa41e94 100644
--- a/Lib/unittest/test/test_setups.py
+++ b/Lib/unittest/test/test_setups.py
@@ -1,7 +1,6 @@
+import io
import sys
-from cStringIO import StringIO
-
import unittest
@@ -13,7 +12,7 @@ class TestSetups(unittest.TestCase):
def getRunner(self):
return unittest.TextTestRunner(resultclass=resultFactory,
- stream=StringIO())
+ stream=io.StringIO())
def runTests(self, *cases):
suite = unittest.TestSuite()
for case in cases:
@@ -501,7 +500,7 @@ class TestSetups(unittest.TestCase):
messages = ('setUpModule', 'tearDownModule', 'setUpClass', 'tearDownClass', 'test_something')
for phase, msg in enumerate(messages):
- with self.assertRaisesRegexp(Exception, msg):
+ with self.assertRaisesRegex(Exception, msg):
suite.debug()
if __name__ == '__main__':
diff --git a/Lib/unittest/test/test_skipping.py b/Lib/unittest/test/test_skipping.py
index d6639d17e55..952240eeede 100644
--- a/Lib/unittest/test/test_skipping.py
+++ b/Lib/unittest/test/test_skipping.py
@@ -66,7 +66,7 @@ class Test_TestSkipping(unittest.TestCase):
self.assertEqual(result.skipped, [(test, "testing")])
self.assertEqual(record, [])
- def test_skip_non_unittest_class_old_style(self):
+ def test_skip_non_unittest_class(self):
@unittest.skip("testing")
class Mixin:
def test_1(self):
@@ -81,21 +81,6 @@ class Test_TestSkipping(unittest.TestCase):
self.assertEqual(result.skipped, [(test, "testing")])
self.assertEqual(record, [])
- def test_skip_non_unittest_class_new_style(self):
- @unittest.skip("testing")
- class Mixin(object):
- def test_1(self):
- record.append(1)
- class Foo(Mixin, unittest.TestCase):
- pass
- record = []
- result = unittest.TestResult()
- test = Foo("test_1")
- suite = unittest.TestSuite([test])
- suite.run(result)
- self.assertEqual(result.skipped, [(test, "testing")])
- self.assertEqual(record, [])
-
def test_expected_failure(self):
class Foo(unittest.TestCase):
@unittest.expectedFailure
@@ -162,7 +147,3 @@ class Test_TestSkipping(unittest.TestCase):
suite = unittest.TestSuite([test])
suite.run(result)
self.assertEqual(result.skipped, [(test, "testing")])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/Lib/unittest/test/test_suite.py b/Lib/unittest/test/test_suite.py
index 72fb527a685..2db978ddb8a 100644
--- a/Lib/unittest/test/test_suite.py
+++ b/Lib/unittest/test/test_suite.py
@@ -26,15 +26,15 @@ class Test_TestSuite(unittest.TestCase, TestEquality):
################################################################
# Used by TestEquality.test_eq
- eq_pairs = [(unittest.TestSuite(), unittest.TestSuite()),
- (unittest.TestSuite(), unittest.TestSuite([])),
- (_mk_TestSuite('test_1'), _mk_TestSuite('test_1'))]
+ eq_pairs = [(unittest.TestSuite(), unittest.TestSuite())
+ ,(unittest.TestSuite(), unittest.TestSuite([]))
+ ,(_mk_TestSuite('test_1'), _mk_TestSuite('test_1'))]
# Used by TestEquality.test_ne
- ne_pairs = [(unittest.TestSuite(), _mk_TestSuite('test_1')),
- (unittest.TestSuite([]), _mk_TestSuite('test_1')),
- (_mk_TestSuite('test_1', 'test_2'), _mk_TestSuite('test_1', 'test_3')),
- (_mk_TestSuite('test_1'), _mk_TestSuite('test_2'))]
+ ne_pairs = [(unittest.TestSuite(), _mk_TestSuite('test_1'))
+ ,(unittest.TestSuite([]), _mk_TestSuite('test_1'))
+ ,(_mk_TestSuite('test_1', 'test_2'), _mk_TestSuite('test_1', 'test_3'))
+ ,(_mk_TestSuite('test_1'), _mk_TestSuite('test_2'))]
################################################################
### /Set up attributes needed by inherited tests
@@ -363,5 +363,6 @@ class Test_TestSuite(unittest.TestCase, TestEquality):
self.assertFalse(result._testRunEntered)
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/unittest/util.py b/Lib/unittest/util.py
index 220a024e903..ccdf0b81fa8 100644
--- a/Lib/unittest/util.py
+++ b/Lib/unittest/util.py
@@ -1,6 +1,6 @@
"""Various utility functions."""
-from collections import namedtuple, OrderedDict
+from collections import namedtuple, OrderedDict
__unittest = True
@@ -14,7 +14,6 @@ def safe_repr(obj, short=False):
return result
return result[:_MAX_LENGTH] + ' [truncated]...'
-
def strclass(cls):
return "%s.%s" % (cls.__module__, cls.__name__)
@@ -59,42 +58,27 @@ def sorted_list_difference(expected, actual):
return missing, unexpected
-def unorderable_list_difference(expected, actual, ignore_duplicate=False):
+def unorderable_list_difference(expected, actual):
"""Same behavior as sorted_list_difference but
for lists of unorderable items (like dicts).
As it does a linear search per item (remove) it
- has O(n*n) performance.
- """
+ has O(n*n) performance."""
missing = []
- unexpected = []
while expected:
item = expected.pop()
try:
actual.remove(item)
except ValueError:
missing.append(item)
- if ignore_duplicate:
- for lst in expected, actual:
- try:
- while True:
- lst.remove(item)
- except ValueError:
- pass
- if ignore_duplicate:
- while actual:
- item = actual.pop()
- unexpected.append(item)
- try:
- while True:
- actual.remove(item)
- except ValueError:
- pass
- return missing, unexpected
# anything left in actual is unexpected
return missing, actual
+def three_way_cmp(x, y):
+ """Return -1 if x < y, 0 if x == y and 1 if x > y"""
+ return (x > y) - (x < y)
+
_Mismatch = namedtuple('Mismatch', 'actual expected value')
def _count_diff_all_purpose(actual, expected):