mock: Apply autospec to a mock's return_value

When creating a mock with a class as an autospec:

mock_foo = mock.Mock(autospec=FooClass)

The autospec is only applied to mock_foo itself, and it will
behave as expected. However, the autospec is not applied to its
return_value and thus, the method validation is not enforced:

mock_foo().lish(some_argument_which_doesnt_exist=42)

This patch addresses this issue, and adds necessary unit tests to
test this behaviour.

Change-Id: Icd96beba5a32001cf33f075b801471c6e7c75898
Related-Bug: #1735588
This commit is contained in:
Claudiu Belu 2018-03-29 04:57:48 -07:00
parent bb78b84c3f
commit 6baff0eda4
2 changed files with 8 additions and 1 deletions

View File

@ -44,13 +44,19 @@ class _AutospecMockMixin(object):
def __init__(self, *args, **kwargs):
super(_AutospecMockMixin, self).__init__(*args, **kwargs)
self.__dict__['_autospec'] = kwargs.get('autospec')
autospec = kwargs.get('autospec')
self.__dict__['_autospec'] = autospec
_mock_methods = self.__dict__['_mock_methods']
if _mock_methods:
# this will allow us to be able to set _mock_check_sig if
# the spec_set argument has been given.
_mock_methods.append('_mock_check_sig')
# callable mocks with autospecs (e.g.: the given autospec is a class)
# should have their return values autospeced as well.
if autospec:
self.return_value.__dict__['_autospec'] = autospec
def __getattr__(self, name):
attr = super(_AutospecMockMixin, self).__getattr__(name)

View File

@ -74,6 +74,7 @@ class MockSanityTestCase(testtools.TestCase):
for spec in [Foo, Foo()]:
foo = mock_cls(autospec=spec)
self._check_autospeced_foo(foo)
self._check_autospeced_foo(foo())
def test_mock_autospec_all_members(self):
self._check_mock_autospec_all_members(mock.Mock)