Skip to content

Commit db5e86a

Browse files
authored
Get mock coverage back to 100% (GH-18228)
* use the `: pass` and `: yield` patterns for code that isn't expected to ever be executed. * The _Call items passed to _AnyComparer are only ever of length two, so assert instead of if/else * fix typo * Fix bug, where stop-without-start patching dict blows up with `TypeError: 'NoneType' object is not iterable`, highlighted by lack of coverage of an except branch. * The fix for bpo-37972 means _Call.count and _Call.index are no longer needed. * add coverage for calling next() on a mock_open with readline.return_value set. * __aiter__ is defined on the Mock so the one on _AsyncIterator is never called.
1 parent a327677 commit db5e86a

File tree

4 files changed

+35
-54
lines changed

4 files changed

+35
-54
lines changed

Lib/unittest/mock.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,8 +1042,7 @@ class _AnyComparer(list):
10421042
the left."""
10431043
def __contains__(self, item):
10441044
for _call in self:
1045-
if len(item) != len(_call):
1046-
continue
1045+
assert len(item) == len(_call)
10471046
if all([
10481047
expected == actual
10491048
for expected, actual in zip(item, _call)
@@ -1856,7 +1855,8 @@ def _unpatch_dict(self):
18561855

18571856
def __exit__(self, *args):
18581857
"""Unpatch the dict."""
1859-
self._unpatch_dict()
1858+
if self._original is not None:
1859+
self._unpatch_dict()
18601860
return False
18611861

18621862

@@ -2168,7 +2168,7 @@ def __init__(self, /, *args, **kwargs):
21682168
self.__dict__['__code__'] = code_mock
21692169

21702170
async def _execute_mock_call(self, /, *args, **kwargs):
2171-
# This is nearly just like super(), except for sepcial handling
2171+
# This is nearly just like super(), except for special handling
21722172
# of coroutines
21732173

21742174
_call = self.call_args
@@ -2541,12 +2541,6 @@ def __getattribute__(self, attr):
25412541
return tuple.__getattribute__(self, attr)
25422542

25432543

2544-
def count(self, /, *args, **kwargs):
2545-
return self.__getattr__('count')(*args, **kwargs)
2546-
2547-
def index(self, /, *args, **kwargs):
2548-
return self.__getattr__('index')(*args, **kwargs)
2549-
25502544
def _get_call_arguments(self):
25512545
if len(self) == 2:
25522546
args, kwargs = self
@@ -2917,9 +2911,6 @@ def __init__(self, iterator):
29172911
code_mock.co_flags = inspect.CO_ITERABLE_COROUTINE
29182912
self.__dict__['__code__'] = code_mock
29192913

2920-
def __aiter__(self):
2921-
return self
2922-
29232914
async def __anext__(self):
29242915
try:
29252916
return next(self.iterator)

Lib/unittest/test/testmock/testasync.py

Lines changed: 18 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,38 +16,28 @@ def tearDownModule():
1616

1717

1818
class AsyncClass:
19-
def __init__(self):
20-
pass
21-
async def async_method(self):
22-
pass
23-
def normal_method(self):
24-
pass
19+
def __init__(self): pass
20+
async def async_method(self): pass
21+
def normal_method(self): pass
2522

2623
@classmethod
27-
async def async_class_method(cls):
28-
pass
24+
async def async_class_method(cls): pass
2925

3026
@staticmethod
31-
async def async_static_method():
32-
pass
27+
async def async_static_method(): pass
3328

3429

3530
class AwaitableClass:
36-
def __await__(self):
37-
yield
31+
def __await__(self): yield
3832

39-
async def async_func():
40-
pass
33+
async def async_func(): pass
4134

42-
async def async_func_args(a, b, *, c):
43-
pass
35+
async def async_func_args(a, b, *, c): pass
4436

45-
def normal_func():
46-
pass
37+
def normal_func(): pass
4738

4839
class NormalClass(object):
49-
def a(self):
50-
pass
40+
def a(self): pass
5141

5242

5343
async_foo_name = f'{__name__}.AsyncClass'
@@ -402,17 +392,15 @@ def test_magicmock_lambda_spec(self):
402392

403393
class AsyncArguments(IsolatedAsyncioTestCase):
404394
async def test_add_return_value(self):
405-
async def addition(self, var):
406-
return var + 1
395+
async def addition(self, var): pass
407396

408397
mock = AsyncMock(addition, return_value=10)
409398
output = await mock(5)
410399

411400
self.assertEqual(output, 10)
412401

413402
async def test_add_side_effect_exception(self):
414-
async def addition(var):
415-
return var + 1
403+
async def addition(var): pass
416404
mock = AsyncMock(addition, side_effect=Exception('err'))
417405
with self.assertRaises(Exception):
418406
await mock(5)
@@ -553,18 +541,14 @@ def test_magic_methods_are_async_functions(self):
553541
class AsyncContextManagerTest(unittest.TestCase):
554542

555543
class WithAsyncContextManager:
556-
async def __aenter__(self, *args, **kwargs):
557-
return self
544+
async def __aenter__(self, *args, **kwargs): pass
558545

559-
async def __aexit__(self, *args, **kwargs):
560-
pass
546+
async def __aexit__(self, *args, **kwargs): pass
561547

562548
class WithSyncContextManager:
563-
def __enter__(self, *args, **kwargs):
564-
return self
549+
def __enter__(self, *args, **kwargs): pass
565550

566-
def __exit__(self, *args, **kwargs):
567-
pass
551+
def __exit__(self, *args, **kwargs): pass
568552

569553
class ProductionCode:
570554
# Example real-world(ish) code
@@ -673,16 +657,9 @@ class WithAsyncIterator(object):
673657
def __init__(self):
674658
self.items = ["foo", "NormalFoo", "baz"]
675659

676-
def __aiter__(self):
677-
return self
678-
679-
async def __anext__(self):
680-
try:
681-
return self.items.pop()
682-
except IndexError:
683-
pass
660+
def __aiter__(self): pass
684661

685-
raise StopAsyncIteration
662+
async def __anext__(self): pass
686663

687664
def test_aiter_set_return_value(self):
688665
mock_iter = AsyncMock(name="tester")

Lib/unittest/test/testmock/testmock.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1868,6 +1868,11 @@ def test_mock_open_using_next(self):
18681868
with self.assertRaises(StopIteration):
18691869
next(f1)
18701870

1871+
def test_mock_open_next_with_readline_with_return_value(self):
1872+
mopen = mock.mock_open(read_data='foo\nbarn')
1873+
mopen.return_value.readline.return_value = 'abc'
1874+
self.assertEqual('abc', next(mopen()))
1875+
18711876
def test_mock_open_write(self):
18721877
# Test exception in file writing write()
18731878
mock_namedtemp = mock.mock_open(mock.MagicMock(name='JLV'))

Lib/unittest/test/testmock/testpatch.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,14 @@ def test_patch_dict_start_stop(self):
770770
self.assertEqual(d, original)
771771

772772

773+
def test_patch_dict_stop_without_start(self):
774+
d = {'foo': 'bar'}
775+
original = d.copy()
776+
patcher = patch.dict(d, [('spam', 'eggs')], clear=True)
777+
self.assertEqual(patcher.stop(), False)
778+
self.assertEqual(d, original)
779+
780+
773781
def test_patch_dict_class_decorator(self):
774782
this = self
775783
d = {'spam': 'eggs'}

0 commit comments

Comments
 (0)