[Python-checkins] Mock 100% coverage (GH-13045)

Chris Withers webhook-mailer at python.org
Wed May 1 18:04:27 EDT 2019


https://github.com/python/cpython/commit/adbf178e49113b2de0042e86a1228560475a65c5
commit: adbf178e49113b2de0042e86a1228560475a65c5
branch: master
author: Chris Withers <chris at withers.org>
committer: GitHub <noreply at github.com>
date: 2019-05-01T23:04:04+01:00
summary:

Mock 100% coverage (GH-13045)

This was achieved by:
* moving many pass statements in tests onto their own lines, so they pass line coverage and can match an easy ignore pattern if branch coverage is added later.
* removing code that cannot be reached.
* removing long-disabled tests.
* removing unused code.
* adding tests for uncovered code

It turned out that removing `if __name__ == '__main__'` blocks that run unittest.main() at the bottom of test files was surprisingly contentious, so they remain and can be filtered out with an appropriate .coveragerc.

files:
M Lib/unittest/mock.py
M Lib/unittest/test/testmock/support.py
M Lib/unittest/test/testmock/testcallable.py
M Lib/unittest/test/testmock/testhelpers.py
M Lib/unittest/test/testmock/testmagicmethods.py
M Lib/unittest/test/testmock/testmock.py
M Lib/unittest/test/testmock/testpatch.py
M Lib/unittest/test/testmock/testsealable.py
M Lib/unittest/test/testmock/testwith.py

diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index 721e91f8cbcb..351aba5d44d7 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -63,10 +63,7 @@ def _get_signature_object(func, as_instance, eat_self):
     """
     if isinstance(func, type) and not as_instance:
         # If it's a type and should be modelled as a type, use __init__.
-        try:
-            func = func.__init__
-        except AttributeError:
-            return None
+        func = func.__init__
         # Skip the `self` argument in __init__
         eat_self = True
     elif not isinstance(func, FunctionTypes):
@@ -147,8 +144,6 @@ def _set_signature(mock, original, instance=False):
     # creates a function with signature (*args, **kwargs) that delegates to a
     # mock. It still does signature checking by calling a lambda with the same
     # signature as the original.
-    if not _callable(original):
-        return
 
     skipfirst = isinstance(original, type)
     result = _get_signature_object(original, instance, skipfirst)
@@ -175,10 +170,6 @@ def checksig(*args, **kwargs):
 def _setup_func(funcopy, mock, sig):
     funcopy.mock = mock
 
-    # can't use isinstance with mocks
-    if not _is_instance_mock(mock):
-        return
-
     def assert_called_with(*args, **kwargs):
         return mock.assert_called_with(*args, **kwargs)
     def assert_called(*args, **kwargs):
@@ -263,12 +254,6 @@ def __reduce__(self):
 _deleted = sentinel.DELETED
 
 
-def _copy(value):
-    if type(value) in (dict, list, tuple, set):
-        return type(value)(value)
-    return value
-
-
 _allowed_names = {
     'return_value', '_mock_return_value', 'side_effect',
     '_mock_side_effect', '_mock_parent', '_mock_new_parent',
@@ -351,8 +336,6 @@ def _check_and_set_parent(parent, value, name, new_name):
 class _MockIter(object):
     def __init__(self, obj):
         self.obj = iter(obj)
-    def __iter__(self):
-        return self
     def __next__(self):
         return next(self.obj)
 
@@ -452,7 +435,7 @@ def _mock_add_spec(self, spec, spec_set, _spec_as_instance=False,
             if isinstance(spec, type):
                 _spec_class = spec
             else:
-                _spec_class = _get_class(spec)
+                _spec_class = type(spec)
             res = _get_signature_object(spec,
                                         _spec_as_instance, _eat_self)
             _spec_signature = res and res[1]
@@ -624,7 +607,7 @@ def _extract_mock_name(self):
         dot = '.'
         if _name_list == ['()']:
             dot = ''
-        seen = set()
+
         while _parent is not None:
             last = _parent
 
@@ -635,11 +618,6 @@ def _extract_mock_name(self):
 
             _parent = _parent._mock_new_parent
 
-            # use ids here so as not to call __hash__ on the mocks
-            if id(_parent) in seen:
-                break
-            seen.add(id(_parent))
-
         _name_list = list(reversed(_name_list))
         _first = last._mock_name or 'mock'
         if len(_name_list) > 1:
@@ -753,8 +731,6 @@ def _format_mock_failure_message(self, args, kwargs):
         message = 'expected call not found.\nExpected: %s\nActual: %s'
         expected_string = self._format_mock_call_signature(args, kwargs)
         call_args = self.call_args
-        if len(call_args) == 3:
-            call_args = call_args[1:]
         actual_string = self._format_mock_call_signature(*call_args)
         return message % (expected_string, actual_string)
 
@@ -992,8 +968,6 @@ def _mock_call(_mock_self, *args, **kwargs):
         self.call_args = _call
         self.call_args_list.append(_call)
 
-        seen = set()
-
         # initial stuff for method_calls:
         do_method_calls = self._mock_parent is not None
         method_call_name = self._mock_name
@@ -1029,13 +1003,6 @@ def _mock_call(_mock_self, *args, **kwargs):
             # follow the parental chain:
             _new_parent = _new_parent._mock_new_parent
 
-            # check we're not in an infinite loop:
-            # ( use ids here so as not to call __hash__ on the mocks)
-            _new_parent_id = id(_new_parent)
-            if _new_parent_id in seen:
-                break
-            seen.add(_new_parent_id)
-
         effect = self.side_effect
         if effect is not None:
             if _is_exception(effect):
@@ -1858,12 +1825,7 @@ def _set_return_value(mock, method, name):
 
     return_calulator = _calculate_return_value.get(name)
     if return_calulator is not None:
-        try:
-            return_value = return_calulator(mock)
-        except AttributeError:
-            # XXXX why do we return AttributeError here?
-            #      set it as a side_effect instead?
-            return_value = AttributeError(name)
+        return_value = return_calulator(mock)
         method.return_value = return_value
         return
 
@@ -1943,10 +1905,6 @@ def __init__(self, name, parent):
         self.name = name
         self.parent = parent
 
-    def __call__(self, *args, **kwargs):
-        m = self.create_mock()
-        return m(*args, **kwargs)
-
     def create_mock(self):
         entry = self.name
         parent = self.parent
@@ -2330,19 +2288,10 @@ def _must_skip(spec, entry, is_type):
         else:
             return False
 
-    # shouldn't get here unless function is a dynamically provided attribute
-    # XXXX untested behaviour
+    # function is a dynamically provided attribute
     return is_type
 
 
-def _get_class(obj):
-    try:
-        return obj.__class__
-    except AttributeError:
-        # it is possible for objects to have no __class__
-        return type(obj)
-
-
 class _SpecState(object):
 
     def __init__(self, spec, spec_set=False, parent=None,
diff --git a/Lib/unittest/test/testmock/support.py b/Lib/unittest/test/testmock/support.py
index f146be244e9c..49986d65dc47 100644
--- a/Lib/unittest/test/testmock/support.py
+++ b/Lib/unittest/test/testmock/support.py
@@ -9,8 +9,7 @@ def is_instance(obj, klass):
 class SomeClass(object):
     class_attribute = None
 
-    def wibble(self):
-        pass
+    def wibble(self): pass
 
 
 class X(object):
diff --git a/Lib/unittest/test/testmock/testcallable.py b/Lib/unittest/test/testmock/testcallable.py
index 34474c4c816e..5eadc0070494 100644
--- a/Lib/unittest/test/testmock/testcallable.py
+++ b/Lib/unittest/test/testmock/testcallable.py
@@ -98,8 +98,7 @@ def test_patch_spec_set_instance(self):
 
     def test_patch_spec_callable_class(self):
         class CallableX(X):
-            def __call__(self):
-                pass
+            def __call__(self): pass
 
         class Sub(CallableX):
             pass
diff --git a/Lib/unittest/test/testmock/testhelpers.py b/Lib/unittest/test/testmock/testhelpers.py
index e321976aeb9f..301bca430c13 100644
--- a/Lib/unittest/test/testmock/testhelpers.py
+++ b/Lib/unittest/test/testmock/testhelpers.py
@@ -12,12 +12,9 @@
 from functools import partial
 
 class SomeClass(object):
-    def one(self, a, b):
-        pass
-    def two(self):
-        pass
-    def three(self, a=None):
-        pass
+    def one(self, a, b): pass
+    def two(self): pass
+    def three(self, a=None): pass
 
 
 
@@ -48,12 +45,9 @@ def test_any_and_datetime(self):
 
     def test_any_mock_calls_comparison_order(self):
         mock = Mock()
-        d = datetime.now()
         class Foo(object):
-            def __eq__(self, other):
-                return False
-            def __ne__(self, other):
-                return True
+            def __eq__(self, other): pass
+            def __ne__(self, other): pass
 
         for d in datetime.now(), Foo():
             mock.reset_mock()
@@ -378,8 +372,7 @@ def test_basic(self):
 
 
     def test_create_autospec_return_value(self):
-        def f():
-            pass
+        def f(): pass
         mock = create_autospec(f, return_value='foo')
         self.assertEqual(mock(), 'foo')
 
@@ -399,8 +392,7 @@ def test_autospec_reset_mock(self):
 
     def test_mocking_unbound_methods(self):
         class Foo(object):
-            def foo(self, foo):
-                pass
+            def foo(self, foo): pass
         p = patch.object(Foo, 'foo')
         mock_foo = p.start()
         Foo().foo(1)
@@ -408,24 +400,6 @@ def foo(self, foo):
         mock_foo.assert_called_with(1)
 
 
-    def test_create_autospec_unbound_methods(self):
-        # see mock issue 128
-        # this is expected to fail until the issue is fixed
-        return
-        class Foo(object):
-            def foo(self):
-                pass
-
-        klass = create_autospec(Foo)
-        instance = klass()
-        self.assertRaises(TypeError, instance.foo, 1)
-
-        # Note: no type checking on the "self" parameter
-        klass.foo(1)
-        klass.foo.assert_called_with(1)
-        self.assertRaises(TypeError, klass.foo)
-
-
     def test_create_autospec_keyword_arguments(self):
         class Foo(object):
             a = 3
@@ -434,8 +408,7 @@ class Foo(object):
 
 
     def test_create_autospec_keyword_only_arguments(self):
-        def foo(a, *, b=None):
-            pass
+        def foo(a, *, b=None): pass
 
         m = create_autospec(foo)
         m(1)
@@ -448,8 +421,7 @@ def foo(a, *, b=None):
 
     def test_function_as_instance_attribute(self):
         obj = SomeClass()
-        def f(a):
-            pass
+        def f(a): pass
         obj.f = f
 
         mock = create_autospec(obj)
@@ -485,13 +457,57 @@ class Sub(SomeClass):
             self._check_someclass_mock(mock)
 
 
+    def test_spec_has_descriptor_returning_function(self):
+
+        class CrazyDescriptor(object):
+
+            def __get__(self, obj, type_):
+                if obj is None:
+                    return lambda x: None
+
+        class MyClass(object):
+
+            some_attr = CrazyDescriptor()
+
+        mock = create_autospec(MyClass)
+        mock.some_attr(1)
+        with self.assertRaises(TypeError):
+            mock.some_attr()
+        with self.assertRaises(TypeError):
+            mock.some_attr(1, 2)
+
+
+    def test_spec_has_function_not_in_bases(self):
+
+        class CrazyClass(object):
+
+            def __dir__(self):
+                return super(CrazyClass, self).__dir__()+['crazy']
+
+            def __getattr__(self, item):
+                if item == 'crazy':
+                    return lambda x: x
+                raise AttributeError(item)
+
+        inst = CrazyClass()
+        with self.assertRaises(AttributeError):
+            inst.other
+        self.assertEqual(inst.crazy(42), 42)
+
+        mock = create_autospec(inst)
+        mock.crazy(42)
+        with self.assertRaises(TypeError):
+            mock.crazy()
+        with self.assertRaises(TypeError):
+            mock.crazy(1, 2)
+
+
     def test_builtin_functions_types(self):
         # we could replace builtin functions / methods with a function
         # with *args / **kwargs signature. Using the builtin method type
         # as a spec seems to work fairly well though.
         class BuiltinSubclass(list):
-            def bar(self, arg):
-                pass
+            def bar(self, arg): pass
             sorted = sorted
             attr = {}
 
@@ -565,17 +581,13 @@ class Sub(SomeClass):
     def test_descriptors(self):
         class Foo(object):
             @classmethod
-            def f(cls, a, b):
-                pass
+            def f(cls, a, b): pass
             @staticmethod
-            def g(a, b):
-                pass
+            def g(a, b): pass
 
-        class Bar(Foo):
-            pass
+        class Bar(Foo): pass
 
-        class Baz(SomeClass, Bar):
-            pass
+        class Baz(SomeClass, Bar): pass
 
         for spec in (Foo, Foo(), Bar, Bar(), Baz, Baz()):
             mock = create_autospec(spec)
@@ -588,8 +600,7 @@ class Baz(SomeClass, Bar):
 
     def test_recursive(self):
         class A(object):
-            def a(self):
-                pass
+            def a(self): pass
             foo = 'foo bar baz'
             bar = foo
 
@@ -611,11 +622,9 @@ def a(self):
 
     def test_spec_inheritance_for_classes(self):
         class Foo(object):
-            def a(self, x):
-                pass
+            def a(self, x): pass
             class Bar(object):
-                def f(self, y):
-                    pass
+                def f(self, y): pass
 
         class_mock = create_autospec(Foo)
 
@@ -695,8 +704,7 @@ def test_builtins(self):
 
 
     def test_function(self):
-        def f(a, b):
-            pass
+        def f(a, b): pass
 
         mock = create_autospec(f)
         self.assertRaises(TypeError, mock)
@@ -726,9 +734,10 @@ class RaiserClass(object):
             def existing(a, b):
                 return a + b
 
+        self.assertEqual(RaiserClass.existing(1, 2), 3)
         s = create_autospec(RaiserClass)
         self.assertRaises(TypeError, lambda x: s.existing(1, 2, 3))
-        s.existing(1, 2)
+        self.assertEqual(s.existing(1, 2), s.existing.return_value)
         self.assertRaises(AttributeError, lambda: s.nonexisting)
 
         # check we can fetch the raiser attribute and it has no spec
@@ -738,8 +747,7 @@ def existing(a, b):
 
     def test_signature_class(self):
         class Foo(object):
-            def __init__(self, a, b=3):
-                pass
+            def __init__(self, a, b=3): pass
 
         mock = create_autospec(Foo)
 
@@ -765,10 +773,8 @@ class Foo(object):
 
     def test_signature_callable(self):
         class Callable(object):
-            def __init__(self, x, y):
-                pass
-            def __call__(self, a):
-                pass
+            def __init__(self, x, y): pass
+            def __call__(self, a): pass
 
         mock = create_autospec(Callable)
         mock(1, 2)
@@ -824,8 +830,7 @@ class Foo(object):
 
     def test_autospec_functions_with_self_in_odd_place(self):
         class Foo(object):
-            def f(a, self):
-                pass
+            def f(a, self): pass
 
         a = create_autospec(Foo)
         a.f(10)
@@ -842,12 +847,9 @@ def __init__(self, value):
                 self.value = value
 
             def __get__(self, obj, cls=None):
-                if obj is None:
-                    return self
-                return self.value
+                return self
 
-            def __set__(self, obj, value):
-                pass
+            def __set__(self, obj, value): pass
 
         class MyProperty(property):
             pass
@@ -856,12 +858,10 @@ class Foo(object):
             __slots__ = ['slot']
 
             @property
-            def prop(self):
-                return 3
+            def prop(self): pass
 
             @MyProperty
-            def subprop(self):
-                return 4
+            def subprop(self): pass
 
             desc = Descriptor(42)
 
@@ -913,8 +913,7 @@ def __getattr__(self, attribute):
 
     def test_spec_inspect_signature(self):
 
-        def myfunc(x, y):
-            pass
+        def myfunc(x, y): pass
 
         mock = create_autospec(myfunc)
         mock(1, 2)
@@ -930,6 +929,7 @@ def test_spec_inspect_signature_annotations(self):
         def foo(a: int, b: int=10, *, c:int) -> int:
             return a + b + c
 
+        self.assertEqual(foo(1, 2 , c=3), 6)
         mock = create_autospec(foo)
         mock(1, 2, c=3)
         mock(1, c=3)
@@ -940,6 +940,42 @@ def foo(a: int, b: int=10, *, c:int) -> int:
         self.assertRaises(TypeError, mock, 1, 2, 3, c=4)
 
 
+    def test_spec_function_no_name(self):
+        func = lambda: 'nope'
+        mock = create_autospec(func)
+        self.assertEqual(mock.__name__, 'funcopy')
+
+
+    def test_spec_function_assert_has_calls(self):
+        def f(a): pass
+        mock = create_autospec(f)
+        mock(1)
+        mock.assert_has_calls([call(1)])
+        with self.assertRaises(AssertionError):
+            mock.assert_has_calls([call(2)])
+
+
+    def test_spec_function_assert_any_call(self):
+        def f(a): pass
+        mock = create_autospec(f)
+        mock(1)
+        mock.assert_any_call(1)
+        with self.assertRaises(AssertionError):
+            mock.assert_any_call(2)
+
+
+    def test_spec_function_reset_mock(self):
+        def f(a): pass
+        rv = Mock()
+        mock = create_autospec(f, return_value=rv)
+        mock(1)(2)
+        self.assertEqual(mock.mock_calls, [call(1)])
+        self.assertEqual(rv.mock_calls, [call(2)])
+        mock.reset_mock()
+        self.assertEqual(mock.mock_calls, [])
+        self.assertEqual(rv.mock_calls, [])
+
+
 class TestCallList(unittest.TestCase):
 
     def test_args_list_contains_call_list(self):
@@ -1019,16 +1055,14 @@ def test_type(self):
 
     def test_call_magic_method(self):
         class Callable:
-            def __call__(self):
-                pass
+            def __call__(self): pass
         instance = Callable()
         self.assertTrue(_callable(instance))
 
     def test_staticmethod(self):
         class WithStaticMethod:
             @staticmethod
-            def staticfunc():
-                pass
+            def staticfunc(): pass
         self.assertTrue(_callable(WithStaticMethod.staticfunc))
 
     def test_non_callable_staticmethod(self):
@@ -1039,8 +1073,7 @@ class BadStaticMethod:
     def test_classmethod(self):
         class WithClassMethod:
             @classmethod
-            def classfunc(cls):
-                pass
+            def classfunc(cls): pass
         self.assertTrue(_callable(WithClassMethod.classfunc))
 
     def test_non_callable_classmethod(self):
diff --git a/Lib/unittest/test/testmock/testmagicmethods.py b/Lib/unittest/test/testmock/testmagicmethods.py
index 69dfe60f7eae..130a3397ba0d 100644
--- a/Lib/unittest/test/testmock/testmagicmethods.py
+++ b/Lib/unittest/test/testmock/testmagicmethods.py
@@ -305,8 +305,7 @@ def test_magic_methods_fspath(self):
 
     def test_magic_methods_and_spec(self):
         class Iterable(object):
-            def __iter__(self):
-                pass
+            def __iter__(self): pass
 
         mock = Mock(spec=Iterable)
         self.assertRaises(AttributeError, lambda: mock.__iter__)
@@ -330,8 +329,7 @@ def set_int():
 
     def test_magic_methods_and_spec_set(self):
         class Iterable(object):
-            def __iter__(self):
-                pass
+            def __iter__(self): pass
 
         mock = Mock(spec_set=Iterable)
         self.assertRaises(AttributeError, lambda: mock.__iter__)
diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py
index 9bef51abd87f..5f917dd20f1d 100644
--- a/Lib/unittest/test/testmock/testmock.py
+++ b/Lib/unittest/test/testmock/testmock.py
@@ -28,16 +28,13 @@ def next(self):
 
 
 class Something(object):
-    def meth(self, a, b, c, d=None):
-        pass
+    def meth(self, a, b, c, d=None): pass
 
     @classmethod
-    def cmeth(cls, a, b, c, d=None):
-        pass
+    def cmeth(cls, a, b, c, d=None): pass
 
     @staticmethod
-    def smeth(a, b, c, d=None):
-        pass
+    def smeth(a, b, c, d=None): pass
 
 
 class MockTest(unittest.TestCase):
@@ -83,6 +80,21 @@ def test_return_value_in_constructor(self):
                           "return value in constructor not honoured")
 
 
+    def test_change_return_value_via_delegate(self):
+        def f(): pass
+        mock = create_autospec(f)
+        mock.mock.return_value = 1
+        self.assertEqual(mock(), 1)
+
+
+    def test_change_side_effect_via_delegate(self):
+        def f(): pass
+        mock = create_autospec(f)
+        mock.mock.side_effect = TypeError()
+        with self.assertRaises(TypeError):
+            mock()
+
+
     def test_repr(self):
         mock = Mock(name='foo')
         self.assertIn('foo', repr(mock))
@@ -161,8 +173,7 @@ def test_autospec_side_effect(self):
         results = [1, 2, 3]
         def effect():
             return results.pop()
-        def f():
-            pass
+        def f(): pass
 
         mock = create_autospec(f)
         mock.side_effect = [1, 2, 3]
@@ -177,8 +188,7 @@ def f():
 
     def test_autospec_side_effect_exception(self):
         # Test for issue 23661
-        def f():
-            pass
+        def f(): pass
 
         mock = create_autospec(f)
         mock.side_effect = ValueError('Bazinga!')
@@ -340,8 +350,7 @@ def test_assert_called_with_any(self):
 
 
     def test_assert_called_with_function_spec(self):
-        def f(a, b, c, d=None):
-            pass
+        def f(a, b, c, d=None): pass
 
         mock = Mock(spec=f)
 
@@ -409,8 +418,7 @@ def test_assert_called_once_with_call_list(self):
 
 
     def test_assert_called_once_with_function_spec(self):
-        def f(a, b, c, d=None):
-            pass
+        def f(a, b, c, d=None): pass
 
         mock = Mock(spec=f)
 
@@ -514,8 +522,7 @@ def test_from_spec(self):
         class Something(object):
             x = 3
             __something__ = None
-            def y(self):
-                pass
+            def y(self): pass
 
         def test_attributes(mock):
             # should work
@@ -601,8 +608,7 @@ def method(self):
 
     def test_customize_wrapped_object_with_side_effect_iterable(self):
         class Real(object):
-            def method(self):
-                raise NotImplementedError()
+            def method(self): pass
 
         real = Real()
         mock = Mock(wraps=real)
@@ -615,8 +621,7 @@ def method(self):
 
     def test_customize_wrapped_object_with_side_effect_exception(self):
         class Real(object):
-            def method(self):
-                raise NotImplementedError()
+            def method(self): pass
 
         real = Real()
         mock = Mock(wraps=real)
@@ -627,9 +632,7 @@ def method(self):
 
     def test_customize_wrapped_object_with_side_effect_function(self):
         class Real(object):
-            def method(self):
-                raise NotImplementedError()
-
+            def method(self): pass
         def side_effect():
             return sentinel.VALUE
 
@@ -642,8 +645,7 @@ def side_effect():
 
     def test_customize_wrapped_object_with_return_value(self):
         class Real(object):
-            def method(self):
-                raise NotImplementedError()
+            def method(self): pass
 
         real = Real()
         mock = Mock(wraps=real)
@@ -655,8 +657,7 @@ def method(self):
     def test_customize_wrapped_object_with_return_value_and_side_effect(self):
         # side_effect should always take precedence over return_value.
         class Real(object):
-            def method(self):
-                raise NotImplementedError()
+            def method(self): pass
 
         real = Real()
         mock = Mock(wraps=real)
@@ -671,8 +672,7 @@ def method(self):
     def test_customize_wrapped_object_with_return_value_and_side_effect2(self):
         # side_effect can return DEFAULT to default to return_value
         class Real(object):
-            def method(self):
-                raise NotImplementedError()
+            def method(self): pass
 
         real = Real()
         mock = Mock(wraps=real)
@@ -684,8 +684,7 @@ def method(self):
 
     def test_customize_wrapped_object_with_return_value_and_side_effect_default(self):
         class Real(object):
-            def method(self):
-                raise NotImplementedError()
+            def method(self): pass
 
         real = Real()
         mock = Mock(wraps=real)
@@ -764,6 +763,26 @@ class X(object):
         self.assertIsInstance(mock, X)
 
 
+    def test_spec_class_no_object_base(self):
+        class X:
+            pass
+
+        mock = Mock(spec=X)
+        self.assertIsInstance(mock, X)
+
+        mock = Mock(spec=X())
+        self.assertIsInstance(mock, X)
+
+        self.assertIs(mock.__class__, X)
+        self.assertEqual(Mock().__class__.__name__, 'Mock')
+
+        mock = Mock(spec_set=X)
+        self.assertIsInstance(mock, X)
+
+        mock = Mock(spec_set=X())
+        self.assertIsInstance(mock, X)
+
+
     def test_setting_attribute_with_spec_set(self):
         class X(object):
             y = 3
@@ -902,15 +921,9 @@ def test_configure_mock(self):
 
     def assertRaisesWithMsg(self, exception, message, func, *args, **kwargs):
         # needed because assertRaisesRegex doesn't work easily with newlines
-        try:
+        with self.assertRaises(exception) as context:
             func(*args, **kwargs)
-        except:
-            instance = sys.exc_info()[1]
-            self.assertIsInstance(instance, exception)
-        else:
-            self.fail('Exception %r not raised' % (exception,))
-
-        msg = str(instance)
+        msg = str(context.exception)
         self.assertEqual(msg, message)
 
 
@@ -1099,6 +1112,18 @@ def test_mock_call_repr(self):
         self.assertEqual(repr(m.mock_calls[2]), 'call.foo().bar().baz.bob()')
 
 
+    def test_mock_call_repr_loop(self):
+        m = Mock()
+        m.foo = m
+        repr(m.foo())
+        self.assertRegex(repr(m.foo()), r"<Mock name='mock\(\)' id='\d+'>")
+
+
+    def test_mock_calls_contains(self):
+        m = Mock()
+        self.assertFalse([call()] in m.mock_calls)
+
+
     def test_subclassing(self):
         class Subclass(Mock):
             pass
@@ -1312,8 +1337,7 @@ def test_assert_has_calls(self):
 
 
     def test_assert_has_calls_with_function_spec(self):
-        def f(a, b, c, d=None):
-            pass
+        def f(a, b, c, d=None): pass
 
         mock = Mock(spec=f)
 
@@ -1371,8 +1395,7 @@ def test_assert_any_call(self):
 
 
     def test_assert_any_call_with_function_spec(self):
-        def f(a, b, c, d=None):
-            pass
+        def f(a, b, c, d=None): pass
 
         mock = Mock(spec=f)
 
@@ -1391,8 +1414,7 @@ def f(a, b, c, d=None):
 
 
     def test_mock_calls_create_autospec(self):
-        def f(a, b):
-            pass
+        def f(a, b): pass
         obj = Iter()
         obj.f = f
 
@@ -1417,12 +1439,10 @@ def test_create_autospec_with_name(self):
     def test_create_autospec_classmethod_and_staticmethod(self):
         class TestClass:
             @classmethod
-            def class_method(cls):
-                pass
+            def class_method(cls): pass
 
             @staticmethod
-            def static_method():
-                pass
+            def static_method(): pass
         for method in ('class_method', 'static_method'):
             with self.subTest(method=method):
                 mock_method = mock.create_autospec(getattr(TestClass, method))
@@ -1848,8 +1868,7 @@ def test_parent_attribute_of_call(self):
 
     def test_parent_propagation_with_create_autospec(self):
 
-        def foo(a, b):
-            pass
+        def foo(a, b): pass
 
         mock = Mock()
         mock.child = create_autospec(foo)
@@ -1878,11 +1897,12 @@ def test_isinstance_under_settrace(self):
         with patch.dict('sys.modules'):
             del sys.modules['unittest.mock']
 
-            def trace(frame, event, arg):
+            # This trace will stop coverage being measured ;-)
+            def trace(frame, event, arg):  # pragma: no cover
                 return trace
 
+            self.addCleanup(sys.settrace, sys.gettrace())
             sys.settrace(trace)
-            self.addCleanup(sys.settrace, None)
 
             from unittest.mock import (
                 Mock, MagicMock, NonCallableMock, NonCallableMagicMock
diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py
index e5abd9bda489..3295c5b2420e 100644
--- a/Lib/unittest/test/testmock/testpatch.py
+++ b/Lib/unittest/test/testmock/testpatch.py
@@ -43,31 +43,24 @@ def __delattr__(self, name):
 
 
 class Foo(object):
-    def __init__(self, a):
-        pass
-    def f(self, a):
-        pass
-    def g(self):
-        pass
+    def __init__(self, a): pass
+    def f(self, a): pass
+    def g(self): pass
     foo = 'bar'
 
     @staticmethod
-    def static_method():
-        return 24
+    def static_method(): pass
 
     @classmethod
-    def class_method(cls):
-        return 42
+    def class_method(cls): pass
 
     class Bar(object):
-        def a(self):
-            pass
+        def a(self): pass
 
 foo_name = '%s.Foo' % __name__
 
 
-def function(a, b=Foo):
-    pass
+def function(a, b=Foo): pass
 
 
 class Container(object):
@@ -370,31 +363,19 @@ def test():
 
 
     def test_patch_wont_create_by_default(self):
-        try:
+        with self.assertRaises(AttributeError):
             @patch('%s.frooble' % builtin_string, sentinel.Frooble)
-            def test():
-                self.assertEqual(frooble, sentinel.Frooble)
+            def test(): pass
 
             test()
-        except AttributeError:
-            pass
-        else:
-            self.fail('Patching non existent attributes should fail')
-
         self.assertRaises(NameError, lambda: frooble)
 
 
     def test_patchobject_wont_create_by_default(self):
-        try:
+        with self.assertRaises(AttributeError):
             @patch.object(SomeClass, 'ord', sentinel.Frooble)
-            def test():
-                self.fail('Patching non existent attributes should fail')
-
+            def test(): pass
             test()
-        except AttributeError:
-            pass
-        else:
-            self.fail('Patching non existent attributes should fail')
         self.assertFalse(hasattr(SomeClass, 'ord'))
 
 
@@ -484,6 +465,9 @@ class Something(object):
             attribute = sentinel.Original
 
         class Foo(object):
+
+            test_class_attr = 'whatever'
+
             def test_method(other_self, mock_something):
                 self.assertEqual(PTModule.something, mock_something,
                                  "unpatched")
@@ -642,8 +626,7 @@ def test_name_preserved(self):
         @patch('%s.SomeClass' % __name__, object(), autospec=True)
         @patch.object(SomeClass, object())
         @patch.dict(foo)
-        def some_name():
-            pass
+        def some_name(): pass
 
         self.assertEqual(some_name.__name__, 'some_name')
 
@@ -654,12 +637,9 @@ def test_patch_with_exception(self):
         @patch.dict(foo, {'a': 'b'})
         def test():
             raise NameError('Konrad')
-        try:
+
+        with self.assertRaises(NameError):
             test()
-        except NameError:
-            pass
-        else:
-            self.fail('NameError not raised by test')
 
         self.assertEqual(foo, {})
 
@@ -689,49 +669,6 @@ def test():
             support.target = original
 
 
-    def test_patch_descriptor(self):
-        # would be some effort to fix this - we could special case the
-        # builtin descriptors: classmethod, property, staticmethod
-        return
-        class Nothing(object):
-            foo = None
-
-        class Something(object):
-            foo = {}
-
-            @patch.object(Nothing, 'foo', 2)
-            @classmethod
-            def klass(cls):
-                self.assertIs(cls, Something)
-
-            @patch.object(Nothing, 'foo', 2)
-            @staticmethod
-            def static(arg):
-                return arg
-
-            @patch.dict(foo)
-            @classmethod
-            def klass_dict(cls):
-                self.assertIs(cls, Something)
-
-            @patch.dict(foo)
-            @staticmethod
-            def static_dict(arg):
-                return arg
-
-        # these will raise exceptions if patching descriptors is broken
-        self.assertEqual(Something.static('f00'), 'f00')
-        Something.klass()
-        self.assertEqual(Something.static_dict('f00'), 'f00')
-        Something.klass_dict()
-
-        something = Something()
-        self.assertEqual(something.static('f00'), 'f00')
-        something.klass()
-        self.assertEqual(something.static_dict('f00'), 'f00')
-        something.klass_dict()
-
-
     def test_patch_spec_set(self):
         @patch('%s.SomeClass' % __name__, spec=SomeClass, spec_set=True)
         def test(MockClass):
@@ -931,17 +868,13 @@ def test_patch_dict_keyword_args(self):
 
     def test_autospec(self):
         class Boo(object):
-            def __init__(self, a):
-                pass
-            def f(self, a):
-                pass
-            def g(self):
-                pass
+            def __init__(self, a): pass
+            def f(self, a): pass
+            def g(self): pass
             foo = 'bar'
 
             class Bar(object):
-                def a(self):
-                    pass
+                def a(self): pass
 
         def _test(mock):
             mock(1)
@@ -1488,20 +1421,17 @@ def test_nested_patch_failure(self):
         @patch.object(Foo, 'g', 1)
         @patch.object(Foo, 'missing', 1)
         @patch.object(Foo, 'f', 1)
-        def thing1():
-            pass
+        def thing1(): pass
 
         @patch.object(Foo, 'missing', 1)
         @patch.object(Foo, 'g', 1)
         @patch.object(Foo, 'f', 1)
-        def thing2():
-            pass
+        def thing2(): pass
 
         @patch.object(Foo, 'g', 1)
         @patch.object(Foo, 'f', 1)
         @patch.object(Foo, 'missing', 1)
-        def thing3():
-            pass
+        def thing3(): pass
 
         for func in thing1, thing2, thing3:
             self.assertRaises(AttributeError, func)
@@ -1520,20 +1450,17 @@ def crasher():
         @patch.object(Foo, 'g', 1)
         @patch.object(Foo, 'foo', new_callable=crasher)
         @patch.object(Foo, 'f', 1)
-        def thing1():
-            pass
+        def thing1(): pass
 
         @patch.object(Foo, 'foo', new_callable=crasher)
         @patch.object(Foo, 'g', 1)
         @patch.object(Foo, 'f', 1)
-        def thing2():
-            pass
+        def thing2(): pass
 
         @patch.object(Foo, 'g', 1)
         @patch.object(Foo, 'f', 1)
         @patch.object(Foo, 'foo', new_callable=crasher)
-        def thing3():
-            pass
+        def thing3(): pass
 
         for func in thing1, thing2, thing3:
             self.assertRaises(NameError, func)
@@ -1559,8 +1486,7 @@ def test_patch_multiple_failure(self):
             patcher.additional_patchers = additionals
 
             @patcher
-            def func():
-                pass
+            def func(): pass
 
             self.assertRaises(AttributeError, func)
             self.assertEqual(Foo.f, original_f)
@@ -1588,8 +1514,7 @@ def crasher():
             patcher.additional_patchers = additionals
 
             @patcher
-            def func():
-                pass
+            def func(): pass
 
             self.assertRaises(NameError, func)
             self.assertEqual(Foo.f, original_f)
@@ -1898,5 +1823,36 @@ def foo(*a, x=0):
             self.assertEqual(foo(), 1)
         self.assertEqual(foo(), 0)
 
+    def test_dotted_but_module_not_loaded(self):
+        # This exercises the AttributeError branch of _dot_lookup.
+
+        # make sure it's there
+        import unittest.test.testmock.support
+        # now make sure it's not:
+        with patch.dict('sys.modules'):
+            del sys.modules['unittest.test.testmock.support']
+            del sys.modules['unittest.test.testmock']
+            del sys.modules['unittest.test']
+            del sys.modules['unittest']
+
+            # now make sure we can patch based on a dotted path:
+            @patch('unittest.test.testmock.support.X')
+            def test(mock):
+                pass
+            test()
+
+
+    def test_invalid_target(self):
+        with self.assertRaises(TypeError):
+            patch('')
+
+
+    def test_cant_set_kwargs_when_passing_a_mock(self):
+        @patch('unittest.test.testmock.support.X', new=object(), x=1)
+        def test(): pass
+        with self.assertRaises(TypeError):
+            test()
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/Lib/unittest/test/testmock/testsealable.py b/Lib/unittest/test/testmock/testsealable.py
index 0e72b32411c6..59f52338d411 100644
--- a/Lib/unittest/test/testmock/testsealable.py
+++ b/Lib/unittest/test/testmock/testsealable.py
@@ -3,15 +3,10 @@
 
 
 class SampleObject:
-    def __init__(self):
-        self.attr_sample1 = 1
-        self.attr_sample2 = 1
 
-    def method_sample1(self):
-        pass
+    def method_sample1(self): pass
 
-    def method_sample2(self):
-        pass
+    def method_sample2(self): pass
 
 
 class TestSealable(unittest.TestCase):
diff --git a/Lib/unittest/test/testmock/testwith.py b/Lib/unittest/test/testmock/testwith.py
index ec4e540dcfd9..37100b8c1834 100644
--- a/Lib/unittest/test/testmock/testwith.py
+++ b/Lib/unittest/test/testmock/testwith.py
@@ -10,6 +10,8 @@
 something_else  = sentinel.SomethingElse
 
 
+class SampleException(Exception): pass
+
 
 class WithTest(unittest.TestCase):
 
@@ -20,14 +22,10 @@ def test_with_statement(self):
 
 
     def test_with_statement_exception(self):
-        try:
+        with self.assertRaises(SampleException):
             with patch('%s.something' % __name__, sentinel.Something2):
                 self.assertEqual(something, sentinel.Something2, "unpatched")
-                raise Exception('pow')
-        except Exception:
-            pass
-        else:
-            self.fail("patch swallowed exception")
+                raise SampleException()
         self.assertEqual(something, sentinel.Something)
 
 
@@ -128,8 +126,7 @@ def test_dict_context_manager(self):
 
     def test_double_patch_instance_method(self):
         class C:
-            def f(self):
-                pass
+            def f(self): pass
 
         c = C()
 



More information about the Python-checkins mailing list