In a test suite I have some mocks created by directly calling the Mock constructor.
Now I would like to use the create_autospec function instead, to gain the additional benefits of autospeccing.
However in one case I encountered unexpected behavior.
Let's assume I have the following minimal class defined, and I want to mock method so that it always returns 0.
class Class:
def method(self):
return 1
Currently I am mocking the class like this:
from unittest.mock import Mock
ClassMock = Mock(Class, **{'return_value.method.return_value': 0})
instance = ClassMock()
and it works as expected:
>>> instance.method()
0
However if I mock the class using create_autospec:
from unittest.mock import create_autospec
ClassMock = create_autospec(Class, **{'return_value.method.return_value': 0})
instance = ClassMock()
the method's return value is not configured:
>>> instance.method()
<MagicMock name='mock().method()' id='139993721092192'>
This seems unexpected to me, because according to the official docs,
create_autospec()also takes arbitrary keyword arguments that are passed to the constructor of the created mock.
So my question is whether I'm missing something or the behavior in this case is not consistent with the documentation.
Edit 1:
As @wim points out in the comments, when mocking a class, its return_value attribute is explicitly overwritten by a recursive call to create_autospec.
https://github.com/python/cpython/blob/v3.9.2/Lib/unittest/mock.py#L2644
This is probably the reason of the above described behavior.
Edit 2:
I also tried to create the instance directly by setting instance=True but this doesn't work either.
>>> instance = create_autospec(Class, instance=True, **{'method.return_value': 0})
>>> instance.method()
<MagicMock name='mock.method()' id='140603529804824'>
First, the mocked method's return value is configured correctly here:
https://github.com/python/cpython/blob/v3.9.2/Lib/unittest/mock.py#L622
but then it's overwritten by a new mock object when applying the class' spec here:
https://github.com/python/cpython/blob/v3.9.2/Lib/unittest/mock.py#L2695