I am trying to mock a property and would like to control the return value of the property according to other state in the object. A small representative example looks like this
import datetime
from pytest_mock import MockFixture
class MyObject:
def __init__(self, name: str):
self._name = name
self._creation_time = datetime.datetime.now()
@property
def creation_time(self) -> datetime.datetime:
# A series of
# calculations
# here
# return_value = ... something
return return_value
def test_ordered_creation_time(mocker: MockFixture) -> None:
def creation_time_side_effect(self) -> datetime.datetime:
if self._name == 'first_created':
return datetime.datetime(2020, 1, 1)
elif self._name == 'second_created':
return datetime.datetime(2020, 2, 1)
mock_creation_time = mocker.patch.object(
MyObject,
'creation_time',
new_callable=mocker.PropertyMock)
mock_creation_time.side_effect = creation_time_side_effect
first_created = MyObject('first_created')
second_created = MyObject('second_created')
assert first_created.creation_time < second_created.creation_time
Running this with pytest gives me
E TypeError: test_ordered_creation_time.<locals>.creation_time_side_effect() missing 1 required positional argument: 'self'
It looks like while using PropertyMock and setting a side_effect function, that function does not have access to the self object.
Is that correct ? If yes, why is that ?
Alternatively, is there another way to inspect the self object while mocking a property
Full error from pytest
====================================================================================================================================================================================== FAILURES ======================================================================================================================================================================================
_____________________________________________________________________________________________________________________________________________________________________________ test_ordered_creation_time _____________________________________________________________________________________________________________________________________________________________________________
mocker = <pytest_mock.plugin.MockerFixture object at 0x103fb1210>
def test_ordered_creation_time(mocker: MockFixture) -> None:
def creation_time_side_effect(self) -> datetime.datetime:
if self._name == 'first_created':
return datetime.datetime(2020, 1, 1)
elif self._name == 'second_created':
return datetime.datetime(2020, 2, 1)
mock_creation_time = mocker.patch.object(
MyObject,
'creation_time',
new_callable=mocker.PropertyMock)
mock_creation_time.side_effect = creation_time_side_effect
first_created = MyObject('first_created')
second_created = MyObject('second_created')
> assert first_created.creation_time < second_created.creation_time
dummy.py:38:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/opt/homebrew/Cellar/[email protected]/3.11.4/Frameworks/Python.framework/Versions/3.11/lib/python3.11/unittest/mock.py:2946: in __get__
return self()
/opt/homebrew/Cellar/[email protected]/3.11.4/Frameworks/Python.framework/Versions/3.11/lib/python3.11/unittest/mock.py:1124: in __call__
return self._mock_call(*args, **kwargs)
/opt/homebrew/Cellar/[email protected]/3.11.4/Frameworks/Python.framework/Versions/3.11/lib/python3.11/unittest/mock.py:1128: in _mock_call
return self._execute_mock_call(*args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <PropertyMock name='creation_time' id='4361753680'>, args = (), kwargs = {}, effect = <function test_ordered_creation_time.<locals>.creation_time_side_effect at 0x103f9e3e0>
def _execute_mock_call(self, /, *args, **kwargs):
# separate from _increment_mock_call so that awaited functions are
# executed separately from their call, also AsyncMock overrides this method
effect = self.side_effect
if effect is not None:
if _is_exception(effect):
raise effect
elif not _callable(effect):
result = next(effect)
if _is_exception(result):
raise result
else:
> result = effect(*args, **kwargs)
E TypeError: test_ordered_creation_time.<locals>.creation_time_side_effect() missing 1 required positional argument: 'self'
/opt/homebrew/Cellar/[email protected]/3.11.4/Frameworks/Python.framework/Versions/3.11/lib/python3.11/unittest/mock.py:1189: TypeError
Just use
PropertyMock+side_effect. Here is an example: