Skip to content

Commit 2b53856

Browse files
committed
cover the rest of the code
1 parent a5c34e2 commit 2b53856

File tree

4 files changed

+136
-2
lines changed

4 files changed

+136
-2
lines changed

Lib/unittest/mock.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2288,8 +2288,7 @@ def _must_skip(spec, entry, is_type):
22882288
else:
22892289
return False
22902290

2291-
# shouldn't get here unless function is a dynamically provided attribute
2292-
# XXXX untested behaviour
2291+
# function is a dynamically provided attribute
22932292
return is_type
22942293

22952294

Lib/unittest/test/testmock/testhelpers.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,51 @@ class Sub(SomeClass):
457457
self._check_someclass_mock(mock)
458458

459459

460+
def test_spec_has_descriptor_returning_function(self):
461+
462+
class CrazyDescriptor(object):
463+
464+
def __get__(self, obj, type_):
465+
if obj is None:
466+
return lambda x: None
467+
468+
class MyClass(object):
469+
470+
some_attr = CrazyDescriptor()
471+
472+
mock = create_autospec(MyClass)
473+
mock.some_attr(1)
474+
with self.assertRaises(TypeError):
475+
mock.some_attr()
476+
with self.assertRaises(TypeError):
477+
mock.some_attr(1, 2)
478+
479+
480+
def test_spec_has_function_not_in_bases(self):
481+
482+
class CrazyClass(object):
483+
484+
def __dir__(self):
485+
return super(CrazyClass, self).__dir__()+['crazy']
486+
487+
def __getattr__(self, item):
488+
if item == 'crazy':
489+
return lambda x: x
490+
raise AttributeError(item)
491+
492+
inst = CrazyClass()
493+
with self.assertRaises(AttributeError):
494+
inst.other
495+
self.assertEqual(inst.crazy(42), 42)
496+
497+
mock = create_autospec(inst)
498+
mock.crazy(42)
499+
with self.assertRaises(TypeError):
500+
mock.crazy()
501+
with self.assertRaises(TypeError):
502+
mock.crazy(1, 2)
503+
504+
460505
def test_builtin_functions_types(self):
461506
# we could replace builtin functions / methods with a function
462507
# with *args / **kwargs signature. Using the builtin method type
@@ -895,6 +940,42 @@ def foo(a: int, b: int=10, *, c:int) -> int:
895940
self.assertRaises(TypeError, mock, 1, 2, 3, c=4)
896941

897942

943+
def test_spec_function_no_name(self):
944+
func = lambda: 'nope'
945+
mock = create_autospec(func)
946+
self.assertEqual(mock.__name__, 'funcopy')
947+
948+
949+
def test_spec_function_assert_has_calls(self):
950+
def f(a): pass
951+
mock = create_autospec(f)
952+
mock(1)
953+
mock.assert_has_calls([call(1)])
954+
with self.assertRaises(AssertionError):
955+
mock.assert_has_calls([call(2)])
956+
957+
958+
def test_spec_function_assert_any_call(self):
959+
def f(a): pass
960+
mock = create_autospec(f)
961+
mock(1)
962+
mock.assert_any_call(1)
963+
with self.assertRaises(AssertionError):
964+
mock.assert_any_call(2)
965+
966+
967+
def test_spec_function_reset_mock(self):
968+
def f(a): pass
969+
rv = Mock()
970+
mock = create_autospec(f, return_value=rv)
971+
mock(1)(2)
972+
self.assertEqual(mock.mock_calls, [call(1)])
973+
self.assertEqual(rv.mock_calls, [call(2)])
974+
mock.reset_mock()
975+
self.assertEqual(mock.mock_calls, [])
976+
self.assertEqual(rv.mock_calls, [])
977+
978+
898979
class TestCallList(unittest.TestCase):
899980

900981
def test_args_list_contains_call_list(self):

Lib/unittest/test/testmock/testmock.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,21 @@ def test_return_value_in_constructor(self):
8080
"return value in constructor not honoured")
8181

8282

83+
def test_change_return_value_via_delegate(self):
84+
def f(): pass
85+
mock = create_autospec(f)
86+
mock.mock.return_value = 1
87+
self.assertEqual(mock(), 1)
88+
89+
90+
def test_change_side_effect_via_delegate(self):
91+
def f(): pass
92+
mock = create_autospec(f)
93+
mock.mock.side_effect = TypeError()
94+
with self.assertRaises(TypeError):
95+
mock()
96+
97+
8398
def test_repr(self):
8499
mock = Mock(name='foo')
85100
self.assertIn('foo', repr(mock))
@@ -1104,6 +1119,11 @@ def test_mock_call_repr_loop(self):
11041119
self.assertRegex(repr(m.foo()), r"<Mock name='mock\(\)' id='\d+'>")
11051120

11061121

1122+
def test_mock_calls_contains(self):
1123+
m = Mock()
1124+
self.assertFalse([call()] in m.mock_calls)
1125+
1126+
11071127
def test_subclassing(self):
11081128
class Subclass(Mock):
11091129
pass

Lib/unittest/test/testmock/testpatch.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,9 @@ class Something(object):
465465
attribute = sentinel.Original
466466

467467
class Foo(object):
468+
469+
test_class_attr = 'whatever'
470+
468471
def test_method(other_self, mock_something):
469472
self.assertEqual(PTModule.something, mock_something,
470473
"unpatched")
@@ -1820,5 +1823,36 @@ def foo(*a, x=0):
18201823
self.assertEqual(foo(), 1)
18211824
self.assertEqual(foo(), 0)
18221825

1826+
def test_dotted_but_module_not_loaded(self):
1827+
# This exercises the AttributeError branch of _dot_lookup.
1828+
1829+
# make sure it's there
1830+
import unittest.test.testmock.support
1831+
# now make sure it's not:
1832+
with patch.dict('sys.modules'):
1833+
del sys.modules['unittest.test.testmock.support']
1834+
del sys.modules['unittest.test.testmock']
1835+
del sys.modules['unittest.test']
1836+
del sys.modules['unittest']
1837+
1838+
# now make sure we can patch based on a dotted path:
1839+
@patch('unittest.test.testmock.support.X')
1840+
def test(mock):
1841+
pass
1842+
test()
1843+
1844+
1845+
def test_invalid_target(self):
1846+
with self.assertRaises(TypeError):
1847+
patch('')
1848+
1849+
1850+
def test_cant_set_kwargs_when_passing_a_mock(self):
1851+
@patch('unittest.test.testmock.support.X', new=object(), x=1)
1852+
def test(): pass
1853+
with self.assertRaises(TypeError):
1854+
test()
1855+
1856+
18231857
if __name__ == '__main__':
18241858
unittest.main()

0 commit comments

Comments
 (0)