diff options
author | Chris Withers <chris@withers.org> | 2019-05-01 22:04:04 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-01 22:04:04 (GMT) |
commit | adbf178e49113b2de0042e86a1228560475a65c5 (patch) | |
tree | 871ac21aec993e310f915cf2781909282a7a03e9 | |
parent | b7378d77289c911ca6a0c0afaf513879002df7d5 (diff) | |
download | cpython-adbf178e49113b2de0042e86a1228560475a65c5.zip cpython-adbf178e49113b2de0042e86a1228560475a65c5.tar.gz cpython-adbf178e49113b2de0042e86a1228560475a65c5.tar.bz2 |
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.
-rw-r--r-- | Lib/unittest/mock.py | 61 | ||||
-rw-r--r-- | Lib/unittest/test/testmock/support.py | 3 | ||||
-rw-r--r-- | Lib/unittest/test/testmock/testcallable.py | 3 | ||||
-rw-r--r-- | Lib/unittest/test/testmock/testhelpers.py | 195 | ||||
-rw-r--r-- | Lib/unittest/test/testmock/testmagicmethods.py | 6 | ||||
-rw-r--r-- | Lib/unittest/test/testmock/testmock.py | 126 | ||||
-rw-r--r-- | Lib/unittest/test/testmock/testpatch.py | 164 | ||||
-rw-r--r-- | Lib/unittest/test/testmock/testsealable.py | 9 | ||||
-rw-r--r-- | Lib/unittest/test/testmock/testwith.py | 13 |
9 files changed, 263 insertions, 317 deletions
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 721e91f..351aba5 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 _set_signature(mock, original, instance=False): 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 @@ _missing = sentinel.MISSING _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 @@ class NonCallableMock(Base): 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 @@ class NonCallableMock(Base): dot = '.' if _name_list == ['()']: dot = '' - seen = set() + while _parent is not None: last = _parent @@ -635,11 +618,6 @@ class NonCallableMock(Base): _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 @@ class NonCallableMock(Base): 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 @@ class CallableMixin(Base): 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 @@ class CallableMixin(Base): # 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 @@ class MagicProxy(object): 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 f146be2..49986d6 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 34474c4..5eadc00 100644 --- a/Lib/unittest/test/testmock/testcallable.py +++ b/Lib/unittest/test/testmock/testcallable.py @@ -98,8 +98,7 @@ class TestCallable(unittest.TestCase): 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 e321976..301bca4 100644 --- a/Lib/unittest/test/testmock/testhelpers.py +++ b/Lib/unittest/test/testmock/testhelpers.py @@ -12,12 +12,9 @@ from datetime import datetime 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 @@ class AnyTest(unittest.TestCase): 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 @@ class SpecSignatureTest(unittest.TestCase): 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 @@ class SpecSignatureTest(unittest.TestCase): 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 @@ class SpecSignatureTest(unittest.TestCase): 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 SpecSignatureTest(unittest.TestCase): 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 @@ class SpecSignatureTest(unittest.TestCase): 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 SpecSignatureTest(unittest.TestCase): 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 SpecSignatureTest(unittest.TestCase): 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 SpecSignatureTest(unittest.TestCase): 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 @@ class SpecSignatureTest(unittest.TestCase): 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 @@ class SpecSignatureTest(unittest.TestCase): 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 SpecSignatureTest(unittest.TestCase): 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 @@ class SpecSignatureTest(unittest.TestCase): 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 SpecSignatureTest(unittest.TestCase): 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 SpecSignatureTest(unittest.TestCase): 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 @@ class SpecSignatureTest(unittest.TestCase): 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 SpecSignatureTest(unittest.TestCase): __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 @@ class SpecSignatureTest(unittest.TestCase): 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 @@ class SpecSignatureTest(unittest.TestCase): 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 @@ class SpecSignatureTest(unittest.TestCase): 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 @@ class TestCallablePredicate(unittest.TestCase): 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 TestCallablePredicate(unittest.TestCase): 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 69dfe60..130a339 100644 --- a/Lib/unittest/test/testmock/testmagicmethods.py +++ b/Lib/unittest/test/testmock/testmagicmethods.py @@ -305,8 +305,7 @@ class TestMockingMagicMethods(unittest.TestCase): 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 @@ class TestMockingMagicMethods(unittest.TestCase): 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 9bef51a..5f917dd 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -28,16 +28,13 @@ class Iter(object): 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 @@ class MockTest(unittest.TestCase): "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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): 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 e5abd9b..3295c5b 100644 --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/testmock/testpatch.py @@ -43,31 +43,24 @@ something_else = sentinel.SomethingElse 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 @@ class PatchTest(unittest.TestCase): 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 PatchTest(unittest.TestCase): 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 @@ class PatchTest(unittest.TestCase): @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 @@ class PatchTest(unittest.TestCase): @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 @@ class PatchTest(unittest.TestCase): 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 @@ class PatchTest(unittest.TestCase): 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 @@ class PatchTest(unittest.TestCase): @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 @@ class PatchTest(unittest.TestCase): @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 @@ class PatchTest(unittest.TestCase): 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 @@ class PatchTest(unittest.TestCase): 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 @@ class PatchTest(unittest.TestCase): 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 0e72b32..59f5233 100644 --- a/Lib/unittest/test/testmock/testsealable.py +++ b/Lib/unittest/test/testmock/testsealable.py @@ -3,15 +3,10 @@ from unittest import mock 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 ec4e540..37100b8 100644 --- a/Lib/unittest/test/testmock/testwith.py +++ b/Lib/unittest/test/testmock/testwith.py @@ -10,6 +10,8 @@ something = sentinel.Something something_else = sentinel.SomethingElse +class SampleException(Exception): pass + class WithTest(unittest.TestCase): @@ -20,14 +22,10 @@ class WithTest(unittest.TestCase): 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 @@ class WithTest(unittest.TestCase): def test_double_patch_instance_method(self): class C: - def f(self): - pass + def f(self): pass c = C() |