summaryrefslogtreecommitdiffstats
path: root/Lib/unittest
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/unittest')
-rw-r--r--Lib/unittest/loader.py56
-rw-r--r--Lib/unittest/mock.py31
-rw-r--r--Lib/unittest/test/test_case.py2
-rw-r--r--Lib/unittest/test/test_discovery.py254
-rw-r--r--Lib/unittest/test/test_loader.py168
-rw-r--r--Lib/unittest/test/test_setups.py7
-rw-r--r--Lib/unittest/test/testmock/testmock.py36
-rw-r--r--Lib/unittest/test/testmock/testpatch.py24
-rw-r--r--Lib/unittest/util.py2
9 files changed, 532 insertions, 48 deletions
diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py
index 808c50e..a8c6492 100644
--- a/Lib/unittest/loader.py
+++ b/Lib/unittest/loader.py
@@ -6,6 +6,7 @@ import sys
import traceback
import types
import functools
+import warnings
from fnmatch import fnmatch
@@ -70,8 +71,30 @@ class TestLoader(object):
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
return loaded_suite
- def loadTestsFromModule(self, module, use_load_tests=True):
+ # XXX After Python 3.5, remove backward compatibility hacks for
+ # use_load_tests deprecation via *args and **kws. See issue 16662.
+ def loadTestsFromModule(self, module, *args, pattern=None, **kws):
"""Return a suite of all tests cases contained in the given module"""
+ # This method used to take an undocumented and unofficial
+ # use_load_tests argument. For backward compatibility, we still
+ # accept the argument (which can also be the first position) but we
+ # ignore it and issue a deprecation warning if it's present.
+ if len(args) > 0 or 'use_load_tests' in kws:
+ warnings.warn('use_load_tests is deprecated and ignored',
+ DeprecationWarning)
+ kws.pop('use_load_tests', None)
+ if len(args) > 1:
+ # Complain about the number of arguments, but don't forget the
+ # required `module` argument.
+ complaint = len(args) + 1
+ raise TypeError('loadTestsFromModule() takes 1 positional argument but {} were given'.format(complaint))
+ if len(kws) != 0:
+ # Since the keyword arguments are unsorted (see PEP 468), just
+ # pick the alphabetically sorted first argument to complain about,
+ # if multiple were given. At least the error message will be
+ # predictable.
+ complaint = sorted(kws)[0]
+ raise TypeError("loadTestsFromModule() got an unexpected keyword argument '{}'".format(complaint))
tests = []
for name in dir(module):
obj = getattr(module, name)
@@ -80,9 +103,9 @@ class TestLoader(object):
load_tests = getattr(module, 'load_tests', None)
tests = self.suiteClass(tests)
- if use_load_tests and load_tests is not None:
+ if load_tests is not None:
try:
- return load_tests(self, tests, None)
+ return load_tests(self, tests, pattern)
except Exception as e:
return _make_failed_load_tests(module.__name__, e,
self.suiteClass)
@@ -325,7 +348,7 @@ class TestLoader(object):
msg = ("%r module incorrectly imported from %r. Expected %r. "
"Is this module globally installed?")
raise ImportError(msg % (mod_name, module_dir, expected_dir))
- yield self.loadTestsFromModule(module)
+ yield self.loadTestsFromModule(module, pattern=pattern)
elif os.path.isdir(full_path):
if (not namespace and
not os.path.isfile(os.path.join(full_path, '__init__.py'))):
@@ -333,26 +356,27 @@ class TestLoader(object):
load_tests = None
tests = None
- if fnmatch(path, pattern):
- # only check load_tests if the package directory itself matches the filter
- name = self._get_name_from_path(full_path)
+ name = self._get_name_from_path(full_path)
+ try:
package = self._get_module_from_name(name)
+ except case.SkipTest as e:
+ yield _make_skipped_test(name, e, self.suiteClass)
+ except:
+ yield _make_failed_import_test(name, self.suiteClass)
+ else:
load_tests = getattr(package, 'load_tests', None)
- tests = self.loadTestsFromModule(package, use_load_tests=False)
-
- if load_tests is None:
+ tests = self.loadTestsFromModule(package, pattern=pattern)
if tests is not None:
# tests loaded from package file
yield tests
+
+ if load_tests is not None:
+ # loadTestsFromModule(package) has load_tests for us.
+ continue
# recurse into the package
yield from self._find_tests(full_path, pattern,
namespace=namespace)
- else:
- try:
- yield load_tests(self, tests, pattern)
- except Exception as e:
- yield _make_failed_load_tests(package.__name__, e,
- self.suiteClass)
+
defaultTestLoader = TestLoader()
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index 5555774..1c2dd1c 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -27,9 +27,13 @@ __version__ = '1.0'
import inspect
import pprint
import sys
+import builtins
+from types import ModuleType
from functools import wraps, partial
+_builtins = {name for name in dir(builtins) if not name.startswith('_')}
+
BaseExceptions = (BaseException,)
if 'java' in sys.platform:
# jython
@@ -375,7 +379,7 @@ class NonCallableMock(Base):
def __init__(
self, spec=None, wraps=None, name=None, spec_set=None,
parent=None, _spec_state=None, _new_name='', _new_parent=None,
- _spec_as_instance=False, _eat_self=None, **kwargs
+ _spec_as_instance=False, _eat_self=None, unsafe=False, **kwargs
):
if _new_parent is None:
_new_parent = parent
@@ -405,6 +409,7 @@ class NonCallableMock(Base):
__dict__['_mock_mock_calls'] = _CallList()
__dict__['method_calls'] = _CallList()
+ __dict__['_mock_unsafe'] = unsafe
if kwargs:
self.configure_mock(**kwargs)
@@ -561,13 +566,16 @@ class NonCallableMock(Base):
def __getattr__(self, name):
- if name == '_mock_methods':
+ if name in {'_mock_methods', '_mock_unsafe'}:
raise AttributeError(name)
elif self._mock_methods is not None:
if name not in self._mock_methods or name in _all_magics:
raise AttributeError("Mock object has no attribute %r" % name)
elif _is_magic(name):
raise AttributeError(name)
+ if not self._mock_unsafe:
+ if name.startswith(('assert', 'assret')):
+ raise AttributeError(name)
result = self._mock_children.get(name)
if result is _deleted:
@@ -750,6 +758,14 @@ class NonCallableMock(Base):
else:
return _call
+ def assert_not_called(_mock_self):
+ """assert that the mock was never called.
+ """
+ self = _mock_self
+ if self.call_count != 0:
+ msg = ("Expected '%s' to not have been called. Called %s times." %
+ (self._mock_name or 'mock', self.call_count))
+ raise AssertionError(msg)
def assert_called_with(_mock_self, *args, **kwargs):
"""assert that the mock was called with the specified arguments.
@@ -1166,6 +1182,9 @@ class _patch(object):
else:
local = True
+ if name in _builtins and isinstance(target, ModuleType):
+ self.create = True
+
if not self.create and original is DEFAULT:
raise AttributeError(
"%s does not have the attribute %r" % (target, name)
@@ -1875,7 +1894,7 @@ def _format_call_signature(name, args, kwargs):
formatted_args = ''
args_string = ', '.join([repr(arg) for arg in args])
kwargs_string = ', '.join([
- '%s=%r' % (key, value) for key, value in kwargs.items()
+ '%s=%r' % (key, value) for key, value in sorted(kwargs.items())
])
if args_string:
formatted_args = args_string
@@ -2016,6 +2035,12 @@ class _Call(tuple):
return _Call(name=name, parent=self, from_kall=False)
+ def count(self, *args, **kwargs):
+ return self.__getattr__('count')(*args, **kwargs)
+
+ def index(self, *args, **kwargs):
+ return self.__getattr__('index')(*args, **kwargs)
+
def __repr__(self):
if not self.from_kall:
name = self.name or 'call'
diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py
index e70dd5b..f6f0dfe 100644
--- a/Lib/unittest/test/test_case.py
+++ b/Lib/unittest/test/test_case.py
@@ -1080,7 +1080,7 @@ test case
# so can't use assertEqual either. Just use assertTrue.
self.assertTrue(sample_text_error == error)
- def testAsertEqualSingleLine(self):
+ def testAssertEqualSingleLine(self):
sample_text = "laden swallows fly slowly"
revised_sample_text = "unladen swallows fly quickly"
sample_text_error = """\
diff --git a/Lib/unittest/test/test_discovery.py b/Lib/unittest/test/test_discovery.py
index abb9066..851f9f7 100644
--- a/Lib/unittest/test/test_discovery.py
+++ b/Lib/unittest/test/test_discovery.py
@@ -68,7 +68,13 @@ class TestDiscovery(unittest.TestCase):
self.addCleanup(restore_isfile)
loader._get_module_from_name = lambda path: path + ' module'
- loader.loadTestsFromModule = lambda module: module + ' tests'
+ orig_load_tests = loader.loadTestsFromModule
+ def loadTestsFromModule(module, pattern=None):
+ # This is where load_tests is called.
+ base = orig_load_tests(module, pattern=pattern)
+ return base + [module + ' tests']
+ loader.loadTestsFromModule = loadTestsFromModule
+ loader.suiteClass = lambda thing: thing
top_level = os.path.abspath('/foo')
loader._top_level_dir = top_level
@@ -76,9 +82,9 @@ class TestDiscovery(unittest.TestCase):
# The test suites found should be sorted alphabetically for reliable
# execution order.
- expected = [name + ' module tests' for name in
- ('test1', 'test2')]
- expected.extend([('test_dir.%s' % name) + ' module tests' for name in
+ expected = [[name + ' module tests'] for name in
+ ('test1', 'test2', 'test_dir')]
+ expected.extend([[('test_dir.%s' % name) + ' module tests'] for name in
('test3', 'test4')])
self.assertEqual(suite, expected)
@@ -116,34 +122,204 @@ class TestDiscovery(unittest.TestCase):
if os.path.basename(path) == 'test_directory':
def load_tests(loader, tests, pattern):
self.load_tests_args.append((loader, tests, pattern))
- return 'load_tests'
+ return [self.path + ' load_tests']
self.load_tests = load_tests
def __eq__(self, other):
return self.path == other.path
loader._get_module_from_name = lambda name: Module(name)
- def loadTestsFromModule(module, use_load_tests):
- if use_load_tests:
- raise self.failureException('use_load_tests should be False for packages')
- return module.path + ' module tests'
+ orig_load_tests = loader.loadTestsFromModule
+ def loadTestsFromModule(module, pattern=None):
+ # This is where load_tests is called.
+ base = orig_load_tests(module, pattern=pattern)
+ return base + [module.path + ' module tests']
loader.loadTestsFromModule = loadTestsFromModule
+ loader.suiteClass = lambda thing: thing
loader._top_level_dir = '/foo'
# this time no '.py' on the pattern so that it can match
# a test package
suite = list(loader._find_tests('/foo', 'test*'))
- # We should have loaded tests from the test_directory package by calling load_tests
- # and directly from the test_directory2 package
+ # We should have loaded tests from the a_directory and test_directory2
+ # directly and via load_tests for the test_directory package, which
+ # still calls the baseline module loader.
self.assertEqual(suite,
- ['load_tests', 'test_directory2' + ' module tests'])
+ [['a_directory module tests'],
+ ['test_directory load_tests',
+ 'test_directory module tests'],
+ ['test_directory2 module tests']])
+
+
# The test module paths should be sorted for reliable execution order
- self.assertEqual(Module.paths, ['test_directory', 'test_directory2'])
+ self.assertEqual(Module.paths,
+ ['a_directory', 'test_directory', 'test_directory2'])
# load_tests should have been called once with loader, tests and pattern
+ # (but there are no tests in our stub module itself, so thats [] at the
+ # time of call.
self.assertEqual(Module.load_tests_args,
- [(loader, 'test_directory' + ' module tests', 'test*')])
+ [(loader, [], 'test*')])
+
+ def test_find_tests_default_calls_package_load_tests(self):
+ loader = unittest.TestLoader()
+
+ original_listdir = os.listdir
+ def restore_listdir():
+ os.listdir = original_listdir
+ original_isfile = os.path.isfile
+ def restore_isfile():
+ os.path.isfile = original_isfile
+ original_isdir = os.path.isdir
+ def restore_isdir():
+ os.path.isdir = original_isdir
+
+ directories = ['a_directory', 'test_directory', 'test_directory2']
+ path_lists = [directories, [], [], []]
+ os.listdir = lambda path: path_lists.pop(0)
+ self.addCleanup(restore_listdir)
+
+ os.path.isdir = lambda path: True
+ self.addCleanup(restore_isdir)
+
+ os.path.isfile = lambda path: os.path.basename(path) not in directories
+ self.addCleanup(restore_isfile)
+
+ class Module(object):
+ paths = []
+ load_tests_args = []
+
+ def __init__(self, path):
+ self.path = path
+ self.paths.append(path)
+ if os.path.basename(path) == 'test_directory':
+ def load_tests(loader, tests, pattern):
+ self.load_tests_args.append((loader, tests, pattern))
+ return [self.path + ' load_tests']
+ self.load_tests = load_tests
+
+ def __eq__(self, other):
+ return self.path == other.path
+
+ loader._get_module_from_name = lambda name: Module(name)
+ orig_load_tests = loader.loadTestsFromModule
+ def loadTestsFromModule(module, pattern=None):
+ # This is where load_tests is called.
+ base = orig_load_tests(module, pattern=pattern)
+ return base + [module.path + ' module tests']
+ loader.loadTestsFromModule = loadTestsFromModule
+ loader.suiteClass = lambda thing: thing
+
+ loader._top_level_dir = '/foo'
+ # this time no '.py' on the pattern so that it can match
+ # a test package
+ suite = list(loader._find_tests('/foo', 'test*.py'))
+
+ # We should have loaded tests from the a_directory and test_directory2
+ # directly and via load_tests for the test_directory package, which
+ # still calls the baseline module loader.
+ self.assertEqual(suite,
+ [['a_directory module tests'],
+ ['test_directory load_tests',
+ 'test_directory module tests'],
+ ['test_directory2 module tests']])
+ # The test module paths should be sorted for reliable execution order
+ self.assertEqual(Module.paths,
+ ['a_directory', 'test_directory', 'test_directory2'])
+
+
+ # load_tests should have been called once with loader, tests and pattern
+ self.assertEqual(Module.load_tests_args,
+ [(loader, [], 'test*.py')])
+
+ def test_find_tests_customise_via_package_pattern(self):
+ # This test uses the example 'do-nothing' load_tests from
+ # https://docs.python.org/3/library/unittest.html#load-tests-protocol
+ # to make sure that that actually works.
+ # Housekeeping
+ original_listdir = os.listdir
+ def restore_listdir():
+ os.listdir = original_listdir
+ self.addCleanup(restore_listdir)
+ original_isfile = os.path.isfile
+ def restore_isfile():
+ os.path.isfile = original_isfile
+ self.addCleanup(restore_isfile)
+ original_isdir = os.path.isdir
+ def restore_isdir():
+ os.path.isdir = original_isdir
+ self.addCleanup(restore_isdir)
+ self.addCleanup(sys.path.remove, '/foo')
+
+ # Test data: we expect the following:
+ # a listdir to find our package, and a isfile and isdir check on it.
+ # a module-from-name call to turn that into a module
+ # followed by load_tests.
+ # then our load_tests will call discover() which is messy
+ # but that finally chains into find_tests again for the child dir -
+ # which is why we don't have a infinite loop.
+ # We expect to see:
+ # the module load tests for both package and plain module called,
+ # and the plain module result nested by the package module load_tests
+ # indicating that it was processed and could have been mutated.
+ vfs = {'/foo': ['my_package'],
+ '/foo/my_package': ['__init__.py', 'test_module.py']}
+ def list_dir(path):
+ return list(vfs[path])
+ os.listdir = list_dir
+ os.path.isdir = lambda path: not path.endswith('.py')
+ os.path.isfile = lambda path: path.endswith('.py')
+
+ class Module(object):
+ paths = []
+ load_tests_args = []
+
+ def __init__(self, path):
+ self.path = path
+ self.paths.append(path)
+ if path.endswith('test_module'):
+ def load_tests(loader, tests, pattern):
+ self.load_tests_args.append((loader, tests, pattern))
+ return [self.path + ' load_tests']
+ else:
+ def load_tests(loader, tests, pattern):
+ self.load_tests_args.append((loader, tests, pattern))
+ # top level directory cached on loader instance
+ __file__ = '/foo/my_package/__init__.py'
+ this_dir = os.path.dirname(__file__)
+ pkg_tests = loader.discover(
+ start_dir=this_dir, pattern=pattern)
+ return [self.path + ' load_tests', tests
+ ] + pkg_tests
+ self.load_tests = load_tests
+
+ def __eq__(self, other):
+ return self.path == other.path
+
+ loader = unittest.TestLoader()
+ loader._get_module_from_name = lambda name: Module(name)
+ loader.suiteClass = lambda thing: thing
+
+ loader._top_level_dir = '/foo'
+ # this time no '.py' on the pattern so that it can match
+ # a test package
+ suite = list(loader._find_tests('/foo', 'test*.py'))
+
+ # We should have loaded tests from both my_package and
+ # my_pacakge.test_module, and also run the load_tests hook in both.
+ # (normally this would be nested TestSuites.)
+ self.assertEqual(suite,
+ [['my_package load_tests', [],
+ ['my_package.test_module load_tests']]])
+ # Parents before children.
+ self.assertEqual(Module.paths,
+ ['my_package', 'my_package.test_module'])
+
+ # load_tests should have been called twice with loader, tests and pattern
+ self.assertEqual(Module.load_tests_args,
+ [(loader, [], 'test*.py'),
+ (loader, [], 'test*.py')])
def test_discover(self):
loader = unittest.TestLoader()
@@ -203,6 +379,17 @@ class TestDiscovery(unittest.TestCase):
sys.path[:] = orig_sys_path
self.addCleanup(restore)
+ def setup_import_issue_package_tests(self, vfs):
+ self.addCleanup(setattr, os, 'listdir', os.listdir)
+ self.addCleanup(setattr, os.path, 'isfile', os.path.isfile)
+ self.addCleanup(setattr, os.path, 'isdir', os.path.isdir)
+ self.addCleanup(sys.path.__setitem__, slice(None), list(sys.path))
+ def list_dir(path):
+ return list(vfs[path])
+ os.listdir = list_dir
+ os.path.isdir = lambda path: not path.endswith('.py')
+ os.path.isfile = lambda path: path.endswith('.py')
+
def test_discover_with_modules_that_fail_to_import(self):
loader = unittest.TestLoader()
@@ -216,6 +403,25 @@ class TestDiscovery(unittest.TestCase):
with self.assertRaises(ImportError):
test.test_this_does_not_exist()
+ def test_discover_with_init_modules_that_fail_to_import(self):
+ vfs = {'/foo': ['my_package'],
+ '/foo/my_package': ['__init__.py', 'test_module.py']}
+ self.setup_import_issue_package_tests(vfs)
+ import_calls = []
+ def _get_module_from_name(name):
+ import_calls.append(name)
+ raise ImportError("Cannot import Name")
+ loader = unittest.TestLoader()
+ loader._get_module_from_name = _get_module_from_name
+ suite = loader.discover('/foo')
+
+ self.assertIn('/foo', sys.path)
+ self.assertEqual(suite.countTestCases(), 1)
+ test = list(list(suite)[0])[0] # extract test from suite
+ with self.assertRaises(ImportError):
+ test.my_package()
+ self.assertEqual(import_calls, ['my_package'])
+
def test_discover_with_module_that_raises_SkipTest_on_import(self):
loader = unittest.TestLoader()
@@ -232,6 +438,26 @@ class TestDiscovery(unittest.TestCase):
suite.run(result)
self.assertEqual(len(result.skipped), 1)
+ def test_discover_with_init_module_that_raises_SkipTest_on_import(self):
+ vfs = {'/foo': ['my_package'],
+ '/foo/my_package': ['__init__.py', 'test_module.py']}
+ self.setup_import_issue_package_tests(vfs)
+ import_calls = []
+ def _get_module_from_name(name):
+ import_calls.append(name)
+ raise unittest.SkipTest('skipperoo')
+ loader = unittest.TestLoader()
+ loader._get_module_from_name = _get_module_from_name
+ suite = loader.discover('/foo')
+
+ self.assertIn('/foo', sys.path)
+ self.assertEqual(suite.countTestCases(), 1)
+ result = unittest.TestResult()
+ suite.run(result)
+ self.assertEqual(len(result.skipped), 1)
+ self.assertEqual(result.testsRun, 1)
+ self.assertEqual(import_calls, ['my_package'])
+
def test_command_line_handling_parseArgs(self):
program = TestableTestProgram()
diff --git a/Lib/unittest/test/test_loader.py b/Lib/unittest/test/test_loader.py
index b62a1b5..7c23414 100644
--- a/Lib/unittest/test/test_loader.py
+++ b/Lib/unittest/test/test_loader.py
@@ -1,9 +1,26 @@
import sys
import types
-
+import warnings
import unittest
+# Decorator used in the deprecation tests to reset the warning registry for
+# test isolation and reproducibility.
+def warningregistry(func):
+ def wrapper(*args, **kws):
+ missing = object()
+ saved = getattr(warnings, '__warningregistry__', missing).copy()
+ try:
+ return func(*args, **kws)
+ finally:
+ if saved is missing:
+ try:
+ del warnings.__warningregistry__
+ except AttributeError:
+ pass
+ else:
+ warnings.__warningregistry__ = saved
+
class Test_TestLoader(unittest.TestCase):
@@ -150,6 +167,7 @@ class Test_TestLoader(unittest.TestCase):
# Check that loadTestsFromModule honors (or not) a module
# with a load_tests function.
+ @warningregistry
def test_loadTestsFromModule__load_tests(self):
m = types.ModuleType('m')
class MyTestCase(unittest.TestCase):
@@ -168,10 +186,144 @@ class Test_TestLoader(unittest.TestCase):
suite = loader.loadTestsFromModule(m)
self.assertIsInstance(suite, unittest.TestSuite)
self.assertEqual(load_tests_args, [loader, suite, None])
+ # With Python 3.5, the undocumented and unofficial use_load_tests is
+ # ignored (and deprecated).
+ load_tests_args = []
+ with warnings.catch_warnings(record=False):
+ warnings.simplefilter('never')
+ suite = loader.loadTestsFromModule(m, use_load_tests=False)
+ self.assertEqual(load_tests_args, [loader, suite, None])
+
+ @warningregistry
+ def test_loadTestsFromModule__use_load_tests_deprecated_positional(self):
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
+
+ load_tests_args = []
+ def load_tests(loader, tests, pattern):
+ self.assertIsInstance(tests, unittest.TestSuite)
+ load_tests_args.extend((loader, tests, pattern))
+ return tests
+ m.load_tests = load_tests
+ # The method still works.
+ loader = unittest.TestLoader()
+ # use_load_tests=True as a positional argument.
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always')
+ suite = loader.loadTestsFromModule(m, False)
+ self.assertIsInstance(suite, unittest.TestSuite)
+ # load_tests was still called because use_load_tests is deprecated
+ # and ignored.
+ self.assertEqual(load_tests_args, [loader, suite, None])
+ # We got a warning.
+ self.assertIs(w[-1].category, DeprecationWarning)
+ self.assertEqual(str(w[-1].message),
+ 'use_load_tests is deprecated and ignored')
+
+ @warningregistry
+ def test_loadTestsFromModule__use_load_tests_deprecated_keyword(self):
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
+
+ load_tests_args = []
+ def load_tests(loader, tests, pattern):
+ self.assertIsInstance(tests, unittest.TestSuite)
+ load_tests_args.extend((loader, tests, pattern))
+ return tests
+ m.load_tests = load_tests
+ # The method still works.
+ loader = unittest.TestLoader()
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always')
+ suite = loader.loadTestsFromModule(m, use_load_tests=False)
+ self.assertIsInstance(suite, unittest.TestSuite)
+ # load_tests was still called because use_load_tests is deprecated
+ # and ignored.
+ self.assertEqual(load_tests_args, [loader, suite, None])
+ # We got a warning.
+ self.assertIs(w[-1].category, DeprecationWarning)
+ self.assertEqual(str(w[-1].message),
+ 'use_load_tests is deprecated and ignored')
+
+ @warningregistry
+ def test_loadTestsFromModule__too_many_positional_args(self):
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
load_tests_args = []
- suite = loader.loadTestsFromModule(m, use_load_tests=False)
- self.assertEqual(load_tests_args, [])
+ def load_tests(loader, tests, pattern):
+ self.assertIsInstance(tests, unittest.TestSuite)
+ load_tests_args.extend((loader, tests, pattern))
+ return tests
+ m.load_tests = load_tests
+ loader = unittest.TestLoader()
+ with self.assertRaises(TypeError) as cm, \
+ warnings.catch_warning(record=True) as w:
+ loader.loadTestsFromModule(m, False, 'testme.*')
+ # We still got the deprecation warning.
+ self.assertIs(w[-1].category, DeprecationWarning)
+ self.assertEqual(str(w[-1].message),
+ 'use_load_tests is deprecated and ignored')
+ # We also got a TypeError for too many positional arguments.
+ self.assertEqual(type(cm.exception), TypeError)
+ self.assertEqual(
+ str(cm.exception),
+ 'loadTestsFromModule() takes 1 positional argument but 3 were given')
+
+ @warningregistry
+ def test_loadTestsFromModule__use_load_tests_other_bad_keyword(self):
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
+
+ load_tests_args = []
+ def load_tests(loader, tests, pattern):
+ self.assertIsInstance(tests, unittest.TestSuite)
+ load_tests_args.extend((loader, tests, pattern))
+ return tests
+ m.load_tests = load_tests
+ loader = unittest.TestLoader()
+ with warnings.catch_warnings():
+ warnings.simplefilter('never')
+ with self.assertRaises(TypeError) as cm:
+ loader.loadTestsFromModule(
+ m, use_load_tests=False, very_bad=True, worse=False)
+ self.assertEqual(type(cm.exception), TypeError)
+ # The error message names the first bad argument alphabetically,
+ # however use_load_tests (which sorts first) is ignored.
+ self.assertEqual(
+ str(cm.exception),
+ "loadTestsFromModule() got an unexpected keyword argument 'very_bad'")
+
+ def test_loadTestsFromModule__pattern(self):
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
+
+ load_tests_args = []
+ def load_tests(loader, tests, pattern):
+ self.assertIsInstance(tests, unittest.TestSuite)
+ load_tests_args.extend((loader, tests, pattern))
+ return tests
+ m.load_tests = load_tests
+
+ loader = unittest.TestLoader()
+ suite = loader.loadTestsFromModule(m, pattern='testme.*')
+ self.assertIsInstance(suite, unittest.TestSuite)
+ self.assertEqual(load_tests_args, [loader, suite, 'testme.*'])
def test_loadTestsFromModule__faulty_load_tests(self):
m = types.ModuleType('m')
@@ -255,7 +407,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromName('unittest.sdasfasfasdf')
except AttributeError as e:
- self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
+ self.assertEqual(str(e), "module 'unittest' has no attribute 'sdasfasfasdf'")
else:
self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
@@ -272,7 +424,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromName('sdasfasfasdf', unittest)
except AttributeError as e:
- self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
+ self.assertEqual(str(e), "module 'unittest' has no attribute 'sdasfasfasdf'")
else:
self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
@@ -635,7 +787,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromNames(['unittest.sdasfasfasdf', 'unittest'])
except AttributeError as e:
- self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
+ self.assertEqual(str(e), "module 'unittest' has no attribute 'sdasfasfasdf'")
else:
self.fail("TestLoader.loadTestsFromNames failed to raise AttributeError")
@@ -654,7 +806,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromNames(['sdasfasfasdf'], unittest)
except AttributeError as e:
- self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
+ self.assertEqual(str(e), "module 'unittest' has no attribute 'sdasfasfasdf'")
else:
self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
@@ -673,7 +825,7 @@ class Test_TestLoader(unittest.TestCase):
try:
loader.loadTestsFromNames(['TestCase', 'sdasfasfasdf'], unittest)
except AttributeError as e:
- self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
+ self.assertEqual(str(e), "module 'unittest' has no attribute 'sdasfasfasdf'")
else:
self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
diff --git a/Lib/unittest/test/test_setups.py b/Lib/unittest/test/test_setups.py
index 392f95e..2df703e 100644
--- a/Lib/unittest/test/test_setups.py
+++ b/Lib/unittest/test/test_setups.py
@@ -111,7 +111,7 @@ class TestSetups(unittest.TestCase):
self.assertEqual(len(result.errors), 1)
error, _ = result.errors[0]
self.assertEqual(str(error),
- 'setUpClass (%s.BrokenTest)' % __name__)
+ 'setUpClass (%s.%s)' % (__name__, BrokenTest.__qualname__))
def test_error_in_teardown_class(self):
class Test(unittest.TestCase):
@@ -144,7 +144,7 @@ class TestSetups(unittest.TestCase):
error, _ = result.errors[0]
self.assertEqual(str(error),
- 'tearDownClass (%s.Test)' % __name__)
+ 'tearDownClass (%s.%s)' % (__name__, Test.__qualname__))
def test_class_not_torndown_when_setup_fails(self):
class Test(unittest.TestCase):
@@ -414,7 +414,8 @@ class TestSetups(unittest.TestCase):
self.assertEqual(len(result.errors), 0)
self.assertEqual(len(result.skipped), 1)
skipped = result.skipped[0][0]
- self.assertEqual(str(skipped), 'setUpClass (%s.Test)' % __name__)
+ self.assertEqual(str(skipped),
+ 'setUpClass (%s.%s)' % (__name__, Test.__qualname__))
def test_skiptest_in_setupmodule(self):
class Test(unittest.TestCase):
diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py
index 23675b9..3a104cb 100644
--- a/Lib/unittest/test/testmock/testmock.py
+++ b/Lib/unittest/test/testmock/testmock.py
@@ -1187,6 +1187,42 @@ class MockTest(unittest.TestCase):
m = mock.create_autospec(object(), name='sweet_func')
self.assertIn('sweet_func', repr(m))
+ #Issue21238
+ def test_mock_unsafe(self):
+ m = Mock()
+ with self.assertRaises(AttributeError):
+ m.assert_foo_call()
+ with self.assertRaises(AttributeError):
+ m.assret_foo_call()
+ m = Mock(unsafe=True)
+ m.assert_foo_call()
+ m.assret_foo_call()
+
+ #Issue21262
+ def test_assert_not_called(self):
+ m = Mock()
+ m.hello.assert_not_called()
+ m.hello()
+ with self.assertRaises(AssertionError):
+ m.hello.assert_not_called()
+
+ #Issue21256 printout of keyword args should be in deterministic order
+ def test_sorted_call_signature(self):
+ m = Mock()
+ m.hello(name='hello', daddy='hero')
+ text = "call(daddy='hero', name='hello')"
+ self.assertEqual(repr(m.hello.call_args), text)
+
+ #Issue21270 overrides tuple methods for mock.call objects
+ def test_override_tuple_methods(self):
+ c = call.count()
+ i = call.index(132,'hello')
+ m = Mock()
+ m.count()
+ m.index(132,"hello")
+ self.assertEqual(m.method_calls[0], c)
+ self.assertEqual(m.method_calls[1], i)
+
def test_mock_add_spec(self):
class _One(object):
one = 1
diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py
index b516f42..28fe86b 100644
--- a/Lib/unittest/test/testmock/testpatch.py
+++ b/Lib/unittest/test/testmock/testpatch.py
@@ -377,7 +377,7 @@ class PatchTest(unittest.TestCase):
def test_patchobject_wont_create_by_default(self):
try:
- @patch.object(SomeClass, 'frooble', sentinel.Frooble)
+ @patch.object(SomeClass, 'ord', sentinel.Frooble)
def test():
self.fail('Patching non existent attributes should fail')
@@ -386,7 +386,27 @@ class PatchTest(unittest.TestCase):
pass
else:
self.fail('Patching non existent attributes should fail')
- self.assertFalse(hasattr(SomeClass, 'frooble'))
+ self.assertFalse(hasattr(SomeClass, 'ord'))
+
+
+ def test_patch_builtins_without_create(self):
+ @patch(__name__+'.ord')
+ def test_ord(mock_ord):
+ mock_ord.return_value = 101
+ return ord('c')
+
+ @patch(__name__+'.open')
+ def test_open(mock_open):
+ m = mock_open.return_value
+ m.read.return_value = 'abcd'
+
+ fobj = open('doesnotexists.txt')
+ data = fobj.read()
+ fobj.close()
+ return data
+
+ self.assertEqual(test_ord(), 101)
+ self.assertEqual(test_open(), 'abcd')
def test_patch_with_static_methods(self):
diff --git a/Lib/unittest/util.py b/Lib/unittest/util.py
index aee498f..45485dc 100644
--- a/Lib/unittest/util.py
+++ b/Lib/unittest/util.py
@@ -52,7 +52,7 @@ def safe_repr(obj, short=False):
return result[:_MAX_LENGTH] + ' [truncated]...'
def strclass(cls):
- return "%s.%s" % (cls.__module__, cls.__name__)
+ return "%s.%s" % (cls.__module__, cls.__qualname__)
def sorted_list_difference(expected, actual):
"""Finds elements in only one or the other of two, sorted input lists.