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.
This commit is contained in:
Chris Withers 2019-05-01 23:04:04 +01:00 committed by GitHub
parent b7378d7728
commit adbf178e49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 263 additions and 317 deletions

View file

@ -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,