| :meth:`assertNotIsInstance(a, b) | ``not isinstance(a, b)`` | 3.2 |
| <TestCase.assertNotIsInstance>` | | |
+-----------------------------------------+-----------------------------+---------------+
+ | :meth:`assertIsSubclass(a, b) | ``issubclass(a, b)`` | 3.14 |
+ | <TestCase.assertIsSubclass>` | | |
+ +-----------------------------------------+-----------------------------+---------------+
+ | :meth:`assertNotIsSubclass(a, b) | ``not issubclass(a, b)`` | 3.14 |
+ | <TestCase.assertNotIsSubclass>` | | |
+ +-----------------------------------------+-----------------------------+---------------+
All the assert methods accept a *msg* argument that, if specified, is used
as the error message on failure (see also :data:`longMessage`).
.. versionadded:: 3.2
+ .. method:: assertIsSubclass(cls, superclass, msg=None)
+ assertNotIsSubclass(cls, superclass, msg=None)
+
+ Test that *cls* is (or is not) a subclass of *superclass* (which can be a
+ class or a tuple of classes, as supported by :func:`issubclass`).
+ To check for the exact type, use :func:`assertIs(cls, superclass) <assertIs>`.
+
+ .. versionadded:: next
+
It is also possible to check the production of exceptions, warnings, and
log messages using the following methods:
| <TestCase.assertCountEqual>` | elements in the same number, | |
| | regardless of their order. | |
+---------------------------------------+--------------------------------+--------------+
+ | :meth:`assertStartsWith(a, b) | ``a.startswith(b)`` | 3.14 |
+ | <TestCase.assertStartsWith>` | | |
+ +---------------------------------------+--------------------------------+--------------+
+ | :meth:`assertNotStartsWith(a, b) | ``not a.startswith(b)`` | 3.14 |
+ | <TestCase.assertNotStartsWith>` | | |
+ +---------------------------------------+--------------------------------+--------------+
+ | :meth:`assertEndsWith(a, b) | ``a.endswith(b)`` | 3.14 |
+ | <TestCase.assertEndsWith>` | | |
+ +---------------------------------------+--------------------------------+--------------+
+ | :meth:`assertNotEndsWith(a, b) | ``not a.endswith(b)`` | 3.14 |
+ | <TestCase.assertNotEndsWith>` | | |
+ +---------------------------------------+--------------------------------+--------------+
+ | :meth:`assertHasAttr(a, b) | ``hastattr(a, b)`` | 3.14 |
+ | <TestCase.assertHasAttr>` | | |
+ +---------------------------------------+--------------------------------+--------------+
+ | :meth:`assertNotHasAttr(a, b) | ``not hastattr(a, b)`` | 3.14 |
+ | <TestCase.assertNotHasAttr>` | | |
+ +---------------------------------------+--------------------------------+--------------+
.. method:: assertAlmostEqual(first, second, places=7, msg=None, delta=None)
.. versionadded:: 3.2
+ .. method:: assertStartsWith(s, prefix, msg=None)
+ .. method:: assertNotStartsWith(s, prefix, msg=None)
+
+ Test that the Unicode or byte string *s* starts (or does not start)
+ with a *prefix*.
+ *prefix* can also be a tuple of strings to try.
+
+ .. versionadded:: next
+
+
+ .. method:: assertEndsWith(s, suffix, msg=None)
+ .. method:: assertNotEndsWith(s, suffix, msg=None)
+
+ Test that the Unicode or byte string *s* ends (or does not end)
+ with a *suffix*.
+ *suffix* can also be a tuple of strings to try.
+
+ .. versionadded:: next
+
+
+ .. method:: assertHasAttr(obj, name, msg=None)
+ .. method:: assertNotHasAttr(obj, name, msg=None)
+
+ Test that the object *obj* has (or has not) an attribute *name*.
+
+ .. versionadded:: next
+
+
.. _type-specific-methods:
The :meth:`assertEqual` method dispatches the equality check for objects of
directory again. It was removed in Python 3.11.
(Contributed by Jacob Walls in :gh:`80958`.)
+* A number of new methods were added in the :class:`~unittest.TestCase` class
+ that provide more specialized tests.
+
+ - :meth:`~unittest.TestCase.assertHasAttr` and
+ :meth:`~unittest.TestCase.assertNotHasAttr` check whether the object
+ has a particular attribute.
+ - :meth:`~unittest.TestCase.assertIsSubclass` and
+ :meth:`~unittest.TestCase.assertNotIsSubclass` check whether the object
+ is a subclass of a particular class, or of one of a tuple of classes.
+ - :meth:`~unittest.TestCase.assertStartsWith`,
+ :meth:`~unittest.TestCase.assertNotStartsWith`,
+ :meth:`~unittest.TestCase.assertEndsWith` and
+ :meth:`~unittest.TestCase.assertNotEndsWith` check whether the Unicode
+ or byte string starts or ends with particular string(s).
+
+ (Contributed by Serhiy Storchaka in :gh:`71339`.)
+
urllib
------
class ClassPropertiesAndMethods(unittest.TestCase):
- def assertHasAttr(self, obj, name):
- self.assertTrue(hasattr(obj, name),
- '%r has no attribute %r' % (obj, name))
-
- def assertNotHasAttr(self, obj, name):
- self.assertFalse(hasattr(obj, name),
- '%r has unexpected attribute %r' % (obj, name))
-
def test_python_dicts(self):
# Testing Python subclass of dict...
self.assertTrue(issubclass(dict, dict))
return out
- def assertEndsWith(self, actual, exp_end):
- '''Ensure that the given "actual" string ends with "exp_end"'''
- self.assertTrue(actual.endswith(exp_end),
- msg='%r did not end with %r' % (actual, exp_end))
-
def assertMultilineMatches(self, actual, pattern):
m = re.match(pattern, actual, re.DOTALL)
if not m:
with self.subTest(path_parts=path_parts):
yield path_parts
- def assertEndsWith(self, string, suffix):
- """Assert that `string` ends with `suffix`.
-
- Used to ignore an architecture-specific UTF-16 byte-order mark."""
- self.assertEqual(string[-len(suffix) :], suffix)
-
def test_read_text(self):
self.assertEqual(
resources.read_text(self.anchor01, 'utf-8.file'),
print("l1=%r\nl2=%r\nignore=%r" % (l1, l2, ignore), file=sys.stderr)
self.fail("%r missing" % missing.pop())
- def assertHasattr(self, obj, attr, ignore):
- ''' succeed iff hasattr(obj,attr) or attr in ignore. '''
- if attr in ignore: return
- if not hasattr(obj, attr): print("???", attr)
- self.assertTrue(hasattr(obj, attr),
- 'expected hasattr(%r, %r)' % (obj, attr))
-
-
def assertHaskey(self, obj, key, ignore):
''' succeed iff key in obj or key in ignore. '''
if key in ignore: return
for name, value in dict.items():
if name in ignore:
continue
- self.assertHasattr(module, name, ignore)
+ self.assertHasAttr(module, name, ignore)
py_item = getattr(module, name)
if isinstance(value, pyclbr.Function):
self.assertIsInstance(py_item, (FunctionType, BuiltinFunctionType))
class BaseTestCase(TestCase):
- def assertIsSubclass(self, cls, class_or_tuple, msg=None):
- if not issubclass(cls, class_or_tuple):
- message = '%r is not a subclass of %r' % (cls, class_or_tuple)
- if msg is not None:
- message += ' : %s' % msg
- raise self.failureException(message)
-
- def assertNotIsSubclass(self, cls, class_or_tuple, msg=None):
- if issubclass(cls, class_or_tuple):
- message = '%r is a subclass of %r' % (cls, class_or_tuple)
- if msg is not None:
- message += ' : %s' % msg
- raise self.failureException(message)
-
def clear_caches(self):
for f in typing._cleanups:
f()
class TypeVarTupleTests(BaseTestCase):
- def assertEndsWith(self, string, tail):
- if not string.endswith(tail):
- self.fail(f"String {string!r} does not end with {tail!r}")
-
def test_name(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(Ts.__name__, 'Ts')
import inspect
import types
+from collections import UserString
from copy import deepcopy
from test import support
self.events.append('tearDown')
+class List(list):
+ pass
+
+
class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
### Set up attributes used by inherited tests
def runTest(self): raise MyException()
def test(self): pass
- self.assertEqual(Test().id()[-13:], '.Test.runTest')
+ self.assertEndsWith(Test().id(), '.Test.runTest')
# test that TestCase can be instantiated with no args
# primarily for use at the interactive interpreter
def runTest(self): raise MyException()
def test(self): pass
- self.assertEqual(Test('test').id()[-10:], '.Test.test')
+ self.assertEndsWith(Test('test').id(), '.Test.test')
# "class TestCase([methodName])"
# ...
self.assertRaises(self.failureException, self.assertIsNot, thing, thing)
def testAssertIsInstance(self):
- thing = []
+ thing = List()
self.assertIsInstance(thing, list)
- self.assertRaises(self.failureException, self.assertIsInstance,
- thing, dict)
+ self.assertIsInstance(thing, (int, list))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertIsInstance(thing, int)
+ self.assertEqual(str(cm.exception),
+ "[] is not an instance of <class 'int'>")
+ with self.assertRaises(self.failureException) as cm:
+ self.assertIsInstance(thing, (int, float))
+ self.assertEqual(str(cm.exception),
+ "[] is not an instance of any of (<class 'int'>, <class 'float'>)")
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertIsInstance(thing, int, 'ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertIsInstance(thing, int, msg='ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
def testAssertNotIsInstance(self):
- thing = []
- self.assertNotIsInstance(thing, dict)
- self.assertRaises(self.failureException, self.assertNotIsInstance,
- thing, list)
+ thing = List()
+ self.assertNotIsInstance(thing, int)
+ self.assertNotIsInstance(thing, (int, float))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotIsInstance(thing, list)
+ self.assertEqual(str(cm.exception),
+ "[] is an instance of <class 'list'>")
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotIsInstance(thing, (int, list))
+ self.assertEqual(str(cm.exception),
+ "[] is an instance of <class 'list'>")
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotIsInstance(thing, list, 'ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotIsInstance(thing, list, msg='ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
+
+ def testAssertIsSubclass(self):
+ self.assertIsSubclass(List, list)
+ self.assertIsSubclass(List, (int, list))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertIsSubclass(List, int)
+ self.assertEqual(str(cm.exception),
+ f"{List!r} is not a subclass of <class 'int'>")
+ with self.assertRaises(self.failureException) as cm:
+ self.assertIsSubclass(List, (int, float))
+ self.assertEqual(str(cm.exception),
+ f"{List!r} is not a subclass of any of (<class 'int'>, <class 'float'>)")
+ with self.assertRaises(self.failureException) as cm:
+ self.assertIsSubclass(1, int)
+ self.assertEqual(str(cm.exception), "1 is not a class")
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertIsSubclass(List, int, 'ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertIsSubclass(List, int, msg='ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
+
+ def testAssertNotIsSubclass(self):
+ self.assertNotIsSubclass(List, int)
+ self.assertNotIsSubclass(List, (int, float))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotIsSubclass(List, list)
+ self.assertEqual(str(cm.exception),
+ f"{List!r} is a subclass of <class 'list'>")
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotIsSubclass(List, (int, list))
+ self.assertEqual(str(cm.exception),
+ f"{List!r} is a subclass of <class 'list'>")
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotIsSubclass(1, int)
+ self.assertEqual(str(cm.exception), "1 is not a class")
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotIsSubclass(List, list, 'ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotIsSubclass(List, list, msg='ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
+
+ def testAssertHasAttr(self):
+ a = List()
+ a.x = 1
+ self.assertHasAttr(a, 'x')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertHasAttr(a, 'y')
+ self.assertEqual(str(cm.exception),
+ "List instance has no attribute 'y'")
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertHasAttr(a, 'y', 'ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertHasAttr(a, 'y', msg='ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
+
+ def testAssertNotHasAttr(self):
+ a = List()
+ a.x = 1
+ self.assertNotHasAttr(a, 'y')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotHasAttr(a, 'x')
+ self.assertEqual(str(cm.exception),
+ "List instance has unexpected attribute 'x'")
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotHasAttr(a, 'x', 'ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotHasAttr(a, 'x', msg='ababahalamaha')
+ self.assertIn('ababahalamaha', str(cm.exception))
def testAssertIn(self):
animals = {'monkey': 'banana', 'cow': 'grass', 'seal': 'fish'}
pass
self.assertIsNone(value)
+ def testAssertStartswith(self):
+ self.assertStartsWith('ababahalamaha', 'ababa')
+ self.assertStartsWith('ababahalamaha', ('x', 'ababa', 'y'))
+ self.assertStartsWith(UserString('ababahalamaha'), 'ababa')
+ self.assertStartsWith(UserString('ababahalamaha'), ('x', 'ababa', 'y'))
+ self.assertStartsWith(bytearray(b'ababahalamaha'), b'ababa')
+ self.assertStartsWith(bytearray(b'ababahalamaha'), (b'x', b'ababa', b'y'))
+ self.assertStartsWith(b'ababahalamaha', bytearray(b'ababa'))
+ self.assertStartsWith(b'ababahalamaha',
+ (bytearray(b'x'), bytearray(b'ababa'), bytearray(b'y')))
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertStartsWith('ababahalamaha', 'amaha')
+ self.assertEqual(str(cm.exception),
+ "'ababahalamaha' doesn't start with 'amaha'")
+ with self.assertRaises(self.failureException) as cm:
+ self.assertStartsWith('ababahalamaha', ('x', 'y'))
+ self.assertEqual(str(cm.exception),
+ "'ababahalamaha' doesn't start with any of ('x', 'y')")
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertStartsWith(b'ababahalamaha', 'ababa')
+ self.assertEqual(str(cm.exception), 'Expected str, not bytes')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertStartsWith(b'ababahalamaha', ('amaha', 'ababa'))
+ self.assertEqual(str(cm.exception), 'Expected str, not bytes')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertStartsWith([], 'ababa')
+ self.assertEqual(str(cm.exception), 'Expected str, not list')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertStartsWith('ababahalamaha', b'ababa')
+ self.assertEqual(str(cm.exception), 'Expected bytes, not str')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertStartsWith('ababahalamaha', (b'amaha', b'ababa'))
+ self.assertEqual(str(cm.exception), 'Expected bytes, not str')
+ with self.assertRaises(TypeError):
+ self.assertStartsWith('ababahalamaha', ord('a'))
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertStartsWith('ababahalamaha', 'amaha', 'abracadabra')
+ self.assertIn('ababahalamaha', str(cm.exception))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertStartsWith('ababahalamaha', 'amaha', msg='abracadabra')
+ self.assertIn('ababahalamaha', str(cm.exception))
+
+ def testAssertNotStartswith(self):
+ self.assertNotStartsWith('ababahalamaha', 'amaha')
+ self.assertNotStartsWith('ababahalamaha', ('x', 'amaha', 'y'))
+ self.assertNotStartsWith(UserString('ababahalamaha'), 'amaha')
+ self.assertNotStartsWith(UserString('ababahalamaha'), ('x', 'amaha', 'y'))
+ self.assertNotStartsWith(bytearray(b'ababahalamaha'), b'amaha')
+ self.assertNotStartsWith(bytearray(b'ababahalamaha'), (b'x', b'amaha', b'y'))
+ self.assertNotStartsWith(b'ababahalamaha', bytearray(b'amaha'))
+ self.assertNotStartsWith(b'ababahalamaha',
+ (bytearray(b'x'), bytearray(b'amaha'), bytearray(b'y')))
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotStartsWith('ababahalamaha', 'ababa')
+ self.assertEqual(str(cm.exception),
+ "'ababahalamaha' starts with 'ababa'")
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotStartsWith('ababahalamaha', ('x', 'ababa', 'y'))
+ self.assertEqual(str(cm.exception),
+ "'ababahalamaha' starts with 'ababa'")
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotStartsWith(b'ababahalamaha', 'ababa')
+ self.assertEqual(str(cm.exception), 'Expected str, not bytes')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotStartsWith(b'ababahalamaha', ('amaha', 'ababa'))
+ self.assertEqual(str(cm.exception), 'Expected str, not bytes')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotStartsWith([], 'ababa')
+ self.assertEqual(str(cm.exception), 'Expected str, not list')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotStartsWith('ababahalamaha', b'ababa')
+ self.assertEqual(str(cm.exception), 'Expected bytes, not str')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotStartsWith('ababahalamaha', (b'amaha', b'ababa'))
+ self.assertEqual(str(cm.exception), 'Expected bytes, not str')
+ with self.assertRaises(TypeError):
+ self.assertNotStartsWith('ababahalamaha', ord('a'))
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotStartsWith('ababahalamaha', 'ababa', 'abracadabra')
+ self.assertIn('ababahalamaha', str(cm.exception))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotStartsWith('ababahalamaha', 'ababa', msg='abracadabra')
+ self.assertIn('ababahalamaha', str(cm.exception))
+
+ def testAssertEndswith(self):
+ self.assertEndsWith('ababahalamaha', 'amaha')
+ self.assertEndsWith('ababahalamaha', ('x', 'amaha', 'y'))
+ self.assertEndsWith(UserString('ababahalamaha'), 'amaha')
+ self.assertEndsWith(UserString('ababahalamaha'), ('x', 'amaha', 'y'))
+ self.assertEndsWith(bytearray(b'ababahalamaha'), b'amaha')
+ self.assertEndsWith(bytearray(b'ababahalamaha'), (b'x', b'amaha', b'y'))
+ self.assertEndsWith(b'ababahalamaha', bytearray(b'amaha'))
+ self.assertEndsWith(b'ababahalamaha',
+ (bytearray(b'x'), bytearray(b'amaha'), bytearray(b'y')))
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertEndsWith('ababahalamaha', 'ababa')
+ self.assertEqual(str(cm.exception),
+ "'ababahalamaha' doesn't end with 'ababa'")
+ with self.assertRaises(self.failureException) as cm:
+ self.assertEndsWith('ababahalamaha', ('x', 'y'))
+ self.assertEqual(str(cm.exception),
+ "'ababahalamaha' doesn't end with any of ('x', 'y')")
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertEndsWith(b'ababahalamaha', 'amaha')
+ self.assertEqual(str(cm.exception), 'Expected str, not bytes')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertEndsWith(b'ababahalamaha', ('ababa', 'amaha'))
+ self.assertEqual(str(cm.exception), 'Expected str, not bytes')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertEndsWith([], 'amaha')
+ self.assertEqual(str(cm.exception), 'Expected str, not list')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertEndsWith('ababahalamaha', b'amaha')
+ self.assertEqual(str(cm.exception), 'Expected bytes, not str')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertEndsWith('ababahalamaha', (b'ababa', b'amaha'))
+ self.assertEqual(str(cm.exception), 'Expected bytes, not str')
+ with self.assertRaises(TypeError):
+ self.assertEndsWith('ababahalamaha', ord('a'))
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertEndsWith('ababahalamaha', 'ababa', 'abracadabra')
+ self.assertIn('ababahalamaha', str(cm.exception))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertEndsWith('ababahalamaha', 'ababa', msg='abracadabra')
+ self.assertIn('ababahalamaha', str(cm.exception))
+
+ def testAssertNotEndswith(self):
+ self.assertNotEndsWith('ababahalamaha', 'ababa')
+ self.assertNotEndsWith('ababahalamaha', ('x', 'ababa', 'y'))
+ self.assertNotEndsWith(UserString('ababahalamaha'), 'ababa')
+ self.assertNotEndsWith(UserString('ababahalamaha'), ('x', 'ababa', 'y'))
+ self.assertNotEndsWith(bytearray(b'ababahalamaha'), b'ababa')
+ self.assertNotEndsWith(bytearray(b'ababahalamaha'), (b'x', b'ababa', b'y'))
+ self.assertNotEndsWith(b'ababahalamaha', bytearray(b'ababa'))
+ self.assertNotEndsWith(b'ababahalamaha',
+ (bytearray(b'x'), bytearray(b'ababa'), bytearray(b'y')))
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotEndsWith('ababahalamaha', 'amaha')
+ self.assertEqual(str(cm.exception),
+ "'ababahalamaha' ends with 'amaha'")
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotEndsWith('ababahalamaha', ('x', 'amaha', 'y'))
+ self.assertEqual(str(cm.exception),
+ "'ababahalamaha' ends with 'amaha'")
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotEndsWith(b'ababahalamaha', 'amaha')
+ self.assertEqual(str(cm.exception), 'Expected str, not bytes')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotEndsWith(b'ababahalamaha', ('ababa', 'amaha'))
+ self.assertEqual(str(cm.exception), 'Expected str, not bytes')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotEndsWith([], 'amaha')
+ self.assertEqual(str(cm.exception), 'Expected str, not list')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotEndsWith('ababahalamaha', b'amaha')
+ self.assertEqual(str(cm.exception), 'Expected bytes, not str')
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotEndsWith('ababahalamaha', (b'ababa', b'amaha'))
+ self.assertEqual(str(cm.exception), 'Expected bytes, not str')
+ with self.assertRaises(TypeError):
+ self.assertNotEndsWith('ababahalamaha', ord('a'))
+
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotEndsWith('ababahalamaha', 'amaha', 'abracadabra')
+ self.assertIn('ababahalamaha', str(cm.exception))
+ with self.assertRaises(self.failureException) as cm:
+ self.assertNotEndsWith('ababahalamaha', 'amaha', msg='abracadabra')
+ self.assertIn('ababahalamaha', str(cm.exception))
+
def testDeprecatedFailMethods(self):
"""Test that the deprecated fail* methods get removed in 3.12"""
deprecated_names = [
loader = unittest.TestLoader()
# This has to be false for the test to succeed
- self.assertFalse('runTest'.startswith(loader.testMethodPrefix))
+ self.assertNotStartsWith('runTest', loader.testMethodPrefix)
suite = loader.loadTestsFromTestCase(Foo)
self.assertIsInstance(suite, loader.suiteClass)
argv=["foobar"],
testRunner=unittest.TextTestRunner(stream=stream),
testLoader=self.TestLoader(self.FooBar))
- self.assertTrue(hasattr(program, 'result'))
+ self.assertHasAttr(program, 'result')
out = stream.getvalue()
self.assertIn('\nFAIL: testFail ', out)
self.assertIn('\nERROR: testError ', out)
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
'expected failures=1, unexpected successes=1)\n')
- self.assertTrue(out.endswith(expected))
+ self.assertEndsWith(out, expected)
@force_not_colorized
def test_Exit(self):
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
'expected failures=1, unexpected successes=1)\n')
- self.assertTrue(out.endswith(expected))
+ self.assertEndsWith(out, expected)
@force_not_colorized
def test_ExitAsDefault(self):
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
'expected failures=1, unexpected successes=1)\n')
- self.assertTrue(out.endswith(expected))
+ self.assertEndsWith(out, expected)
@force_not_colorized
def test_ExitSkippedSuite(self):
self.assertEqual(cm.exception.code, 0)
out = stream.getvalue()
expected = '\n\nOK (skipped=1)\n'
- self.assertTrue(out.endswith(expected))
+ self.assertEndsWith(out, expected)
@force_not_colorized
def test_ExitEmptySuite(self):
self.assertTrue(result.failfast)
result = runner.run(test)
stream.flush()
- self.assertTrue(stream.getvalue().endswith('\n\nOK\n'))
+ self.assertEndsWith(stream.getvalue(), '\n\nOK\n')
class Test_TextTestResult(unittest.TestCase):
def test_magicmock_has_async_magic_methods(self):
m_mock = MagicMock()
- self.assertTrue(hasattr(m_mock, "__aenter__"))
- self.assertTrue(hasattr(m_mock, "__aexit__"))
- self.assertTrue(hasattr(m_mock, "__anext__"))
+ self.assertHasAttr(m_mock, "__aenter__")
+ self.assertHasAttr(m_mock, "__aexit__")
+ self.assertHasAttr(m_mock, "__anext__")
def test_asyncmock_has_sync_magic_methods(self):
a_mock = AsyncMock()
- self.assertTrue(hasattr(a_mock, "__enter__"))
- self.assertTrue(hasattr(a_mock, "__exit__"))
- self.assertTrue(hasattr(a_mock, "__next__"))
- self.assertTrue(hasattr(a_mock, "__len__"))
+ self.assertHasAttr(a_mock, "__enter__")
+ self.assertHasAttr(a_mock, "__exit__")
+ self.assertHasAttr(a_mock, "__next__")
+ self.assertHasAttr(a_mock, "__len__")
def test_magic_methods_are_async_functions(self):
m_mock = MagicMock()
def test_non_callable(self):
for mock in NonCallableMagicMock(), NonCallableMock():
self.assertRaises(TypeError, mock)
- self.assertFalse(hasattr(mock, '__call__'))
+ self.assertNotHasAttr(mock, '__call__')
self.assertIn(mock.__class__.__name__, repr(mock))
def test_hierarchy(self):
- self.assertTrue(issubclass(MagicMock, Mock))
- self.assertTrue(issubclass(NonCallableMagicMock, NonCallableMock))
+ self.assertIsSubclass(MagicMock, Mock)
+ self.assertIsSubclass(NonCallableMagicMock, NonCallableMock)
def test_attributes(self):
one = NonCallableMock()
- self.assertTrue(issubclass(type(one.one), Mock))
+ self.assertIsSubclass(type(one.one), Mock)
two = NonCallableMagicMock()
- self.assertTrue(issubclass(type(two.two), MagicMock))
+ self.assertIsSubclass(type(two.two), MagicMock)
def test_subclasses(self):
pass
one = MockSub()
- self.assertTrue(issubclass(type(one.one), MockSub))
+ self.assertIsSubclass(type(one.one), MockSub)
class MagicSub(MagicMock):
pass
two = MagicSub()
- self.assertTrue(issubclass(type(two.two), MagicSub))
+ self.assertIsSubclass(type(two.two), MagicSub)
def test_patch_spec(self):
proxy = Foo()
autospec = create_autospec(proxy)
- self.assertFalse(hasattr(autospec, '__name__'))
+ self.assertNotHasAttr(autospec, '__name__')
def test_autospec_signature_staticmethod(self):
def test_deleting_magic_methods(self):
mock = Mock()
- self.assertFalse(hasattr(mock, '__getitem__'))
+ self.assertNotHasAttr(mock, '__getitem__')
mock.__getitem__ = Mock()
- self.assertTrue(hasattr(mock, '__getitem__'))
+ self.assertHasAttr(mock, '__getitem__')
del mock.__getitem__
- self.assertFalse(hasattr(mock, '__getitem__'))
+ self.assertNotHasAttr(mock, '__getitem__')
def test_magicmock_del(self):
self.assertEqual(list(mock), [1, 2, 3])
getattr(mock, '__bool__').return_value = False
- self.assertFalse(hasattr(mock, '__nonzero__'))
+ self.assertNotHasAttr(mock, '__nonzero__')
self.assertFalse(bool(mock))
for entry in _magics:
- self.assertTrue(hasattr(mock, entry))
- self.assertFalse(hasattr(mock, '__imaginary__'))
+ self.assertHasAttr(mock, entry)
+ self.assertNotHasAttr(mock, '__imaginary__')
def test_magic_mock_equality(self):
def test_attribute_deletion(self):
for mock in (Mock(), MagicMock(), NonCallableMagicMock(),
NonCallableMock()):
- self.assertTrue(hasattr(mock, 'm'))
+ self.assertHasAttr(mock, 'm')
del mock.m
- self.assertFalse(hasattr(mock, 'm'))
+ self.assertNotHasAttr(mock, 'm')
del mock.f
- self.assertFalse(hasattr(mock, 'f'))
+ self.assertNotHasAttr(mock, 'f')
self.assertRaises(AttributeError, getattr, mock, 'f')
for mock in (Mock(), MagicMock(), NonCallableMagicMock(),
NonCallableMock()):
mock.foo = 3
- self.assertTrue(hasattr(mock, 'foo'))
+ self.assertHasAttr(mock, 'foo')
self.assertEqual(mock.foo, 3)
del mock.foo
- self.assertFalse(hasattr(mock, 'foo'))
+ self.assertNotHasAttr(mock, 'foo')
mock.foo = 4
- self.assertTrue(hasattr(mock, 'foo'))
+ self.assertHasAttr(mock, 'foo')
self.assertEqual(mock.foo, 4)
del mock.foo
- self.assertFalse(hasattr(mock, 'foo'))
+ self.assertNotHasAttr(mock, 'foo')
def test_mock_raises_when_deleting_nonexistent_attribute(self):
mock.child = True
del mock.child
mock.reset_mock()
- self.assertFalse(hasattr(mock, 'child'))
+ self.assertNotHasAttr(mock, 'child')
def test_class_assignable(self):
self.assertEqual(SomeClass.frooble, sentinel.Frooble)
test()
- self.assertFalse(hasattr(SomeClass, 'frooble'))
+ self.assertNotHasAttr(SomeClass, 'frooble')
def test_patch_wont_create_by_default(self):
@patch.object(SomeClass, 'ord', sentinel.Frooble)
def test(): pass
test()
- self.assertFalse(hasattr(SomeClass, 'ord'))
+ self.assertNotHasAttr(SomeClass, 'ord')
def test_patch_builtins_without_create(self):
finally:
patcher.stop()
- self.assertFalse(hasattr(Foo, 'blam'))
+ self.assertNotHasAttr(Foo, 'blam')
def test_patch_multiple_spec_set(self):
result = f.read()
return result
- def assertEndsWith(self, string, tail):
- if not string.endswith(tail):
- self.fail(f"String {string!r} does not end with {tail!r}")
-
class BasicTest(BaseTest):
"""Test venv module functionality."""
"""Same as self.assertTrue(isinstance(obj, cls)), with a nicer
default message."""
if not isinstance(obj, cls):
- standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls)
+ if isinstance(cls, tuple):
+ standardMsg = f'{safe_repr(obj)} is not an instance of any of {cls!r}'
+ else:
+ standardMsg = f'{safe_repr(obj)} is not an instance of {cls!r}'
self.fail(self._formatMessage(msg, standardMsg))
def assertNotIsInstance(self, obj, cls, msg=None):
"""Included for symmetry with assertIsInstance."""
if isinstance(obj, cls):
- standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls)
+ if isinstance(cls, tuple):
+ for x in cls:
+ if isinstance(obj, x):
+ cls = x
+ break
+ standardMsg = f'{safe_repr(obj)} is an instance of {cls!r}'
+ self.fail(self._formatMessage(msg, standardMsg))
+
+ def assertIsSubclass(self, cls, superclass, msg=None):
+ try:
+ if issubclass(cls, superclass):
+ return
+ except TypeError:
+ if not isinstance(cls, type):
+ self.fail(self._formatMessage(msg, f'{cls!r} is not a class'))
+ raise
+ if isinstance(superclass, tuple):
+ standardMsg = f'{cls!r} is not a subclass of any of {superclass!r}'
+ else:
+ standardMsg = f'{cls!r} is not a subclass of {superclass!r}'
+ self.fail(self._formatMessage(msg, standardMsg))
+
+ def assertNotIsSubclass(self, cls, superclass, msg=None):
+ try:
+ if not issubclass(cls, superclass):
+ return
+ except TypeError:
+ if not isinstance(cls, type):
+ self.fail(self._formatMessage(msg, f'{cls!r} is not a class'))
+ raise
+ if isinstance(superclass, tuple):
+ for x in superclass:
+ if issubclass(cls, x):
+ superclass = x
+ break
+ standardMsg = f'{cls!r} is a subclass of {superclass!r}'
+ self.fail(self._formatMessage(msg, standardMsg))
+
+ def assertHasAttr(self, obj, name, msg=None):
+ if not hasattr(obj, name):
+ if isinstance(obj, types.ModuleType):
+ standardMsg = f'module {obj.__name__!r} has no attribute {name!r}'
+ else:
+ standardMsg = f'{type(obj).__name__} instance has no attribute {name!r}'
+ self.fail(self._formatMessage(msg, standardMsg))
+
+ def assertNotHasAttr(self, obj, name, msg=None):
+ if hasattr(obj, name):
+ if isinstance(obj, types.ModuleType):
+ standardMsg = f'module {obj.__name__!r} has unexpected attribute {name!r}'
+ else:
+ standardMsg = f'{type(obj).__name__} instance has unexpected attribute {name!r}'
self.fail(self._formatMessage(msg, standardMsg))
def assertRaisesRegex(self, expected_exception, expected_regex,
msg = self._formatMessage(msg, standardMsg)
raise self.failureException(msg)
+ def _tail_type_check(self, s, tails, msg):
+ if not isinstance(tails, tuple):
+ tails = (tails,)
+ for tail in tails:
+ if isinstance(tail, str):
+ if not isinstance(s, str):
+ self.fail(self._formatMessage(msg,
+ f'Expected str, not {type(s).__name__}'))
+ elif isinstance(tail, (bytes, bytearray)):
+ if not isinstance(s, (bytes, bytearray)):
+ self.fail(self._formatMessage(msg,
+ f'Expected bytes, not {type(s).__name__}'))
+
+ def assertStartsWith(self, s, prefix, msg=None):
+ try:
+ if s.startswith(prefix):
+ return
+ except (AttributeError, TypeError):
+ self._tail_type_check(s, prefix, msg)
+ raise
+ a = safe_repr(s, short=True)
+ b = safe_repr(prefix)
+ if isinstance(prefix, tuple):
+ standardMsg = f"{a} doesn't start with any of {b}"
+ else:
+ standardMsg = f"{a} doesn't start with {b}"
+ self.fail(self._formatMessage(msg, standardMsg))
+
+ def assertNotStartsWith(self, s, prefix, msg=None):
+ try:
+ if not s.startswith(prefix):
+ return
+ except (AttributeError, TypeError):
+ self._tail_type_check(s, prefix, msg)
+ raise
+ if isinstance(prefix, tuple):
+ for x in prefix:
+ if s.startswith(x):
+ prefix = x
+ break
+ a = safe_repr(s, short=True)
+ b = safe_repr(prefix)
+ self.fail(self._formatMessage(msg, f"{a} starts with {b}"))
+
+ def assertEndsWith(self, s, suffix, msg=None):
+ try:
+ if s.endswith(suffix):
+ return
+ except (AttributeError, TypeError):
+ self._tail_type_check(s, suffix, msg)
+ raise
+ a = safe_repr(s, short=True)
+ b = safe_repr(suffix)
+ if isinstance(suffix, tuple):
+ standardMsg = f"{a} doesn't end with any of {b}"
+ else:
+ standardMsg = f"{a} doesn't end with {b}"
+ self.fail(self._formatMessage(msg, standardMsg))
+
+ def assertNotEndsWith(self, s, suffix, msg=None):
+ try:
+ if not s.endswith(suffix):
+ return
+ except (AttributeError, TypeError):
+ self._tail_type_check(s, suffix, msg)
+ raise
+ if isinstance(suffix, tuple):
+ for x in suffix:
+ if s.endswith(x):
+ suffix = x
+ break
+ a = safe_repr(s, short=True)
+ b = safe_repr(suffix)
+ self.fail(self._formatMessage(msg, f"{a} ends with {b}"))
class FunctionTestCase(TestCase):
--- /dev/null
+Add new assertion methods for :mod:`unittest`:
+:meth:`~unittest.TestCase.assertHasAttr`,
+:meth:`~unittest.TestCase.assertNotHasAttr`,
+:meth:`~unittest.TestCase.assertIsSubclass`,
+:meth:`~unittest.TestCase.assertNotIsSubclass`
+:meth:`~unittest.TestCase.assertStartsWith`,
+:meth:`~unittest.TestCase.assertNotStartsWith`,
+:meth:`~unittest.TestCase.assertEndsWith` and
+:meth:`~unittest.TestCase.assertNotEndsWith`.