William Edwards
William Edwards

Reputation: 21

How to pass `self` to PropertyMock?

When mocking a function, I can pass self with autospec=True:

def do_thing_side_effect(self):
  pass

mocker.patch('module.class.do_thing', side_effect=do_thing_side_effect, autospec=True)

When mocking a property getter, I am unable to pass self with either autospec=True or spec=True:

def thing_side_effect(self):
  pass

mocker.patch('module.class.thing', new=mocker.PropertyMock(side_effect=thing_side_effect, autospec=True))

This yields:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/unittest/mock.py", line 2848, in __get__
    return self()
  File "/usr/local/lib/python3.9/unittest/mock.py", line 1092, in __call__
    return self._mock_call(*args, **kwargs)
  File "/usr/local/lib/python3.9/unittest/mock.py", line 1096, in _mock_call
    return self._execute_mock_call(*args, **kwargs)
  File "/usr/local/lib/python3.9/unittest/mock.py", line 1157, in _execute_mock_call
    result = effect(*args, **kwargs)
TypeError: thing_side_effect() missing 1 required positional argument: 'self'

Using spec instead of autospec causes the same error:

from module import class

def thing_side_effect(self):
  pass

mocker.patch('module.class.thing', new=mocker.PropertyMock(side_effect=thing_side_effect, spec=class.thing))

Using spec + new_callable instead of new causes the same error:

from module import class

def thing_side_effect(self):
  pass

mocker.patch('module.class.thing', spec=mocker.create_autospec(class.thing, side_effect=thing_side_effect, new_callable=mocker.PropertyMock)

Upvotes: 2

Views: 208

Answers (2)

LondonRob
LondonRob

Reputation: 78923

By passing a class whose __get__ method does the side effect you want you can make this work, although I'm sure there's a more "built-in" to do it (but I haven't found what that is.)

from unittest.mock import patch, PropertyMock


class ThingSideEffect:
    def __get__(self, instance, instance_class):
        pass

patch('module.class.thing', new_callable=PropertyMock(side_effect=ThingSideEffect)))

That will drop you into __get__ when you request the property from your class instance.

Upvotes: 0

Nimrod Shanny
Nimrod Shanny

Reputation: 609

If i understand you correctly, in your case i think it would be best to use patch.object

with patch.object(module.class, 'thing_side_effect', new_callable=PropertyMock) as thing_side_effect_mock:
    thing_side_effect_mock.side_effect = "what ever you want to return here"

Good luck :)

Upvotes: 2

Related Questions