python mock property setter while wrapping it

  • Last Update :
  • Techknowledgy :

You need to replace the whole property object; you cannot simply replace the setter. this means you'll need to provide a new property object, where the setter is your mock wrapper for the original setter (accessed by the property.fset attribute):

setter_mock = Mock(wraps = SomeClass.value.fset)
mock_property = SomeClass.value.setter(setter_mock)
with patch.object(SomeClass, 'value', mock_property):
   instance.value = 1
setter_mock.assert_called_with(instance, 1)

Here's another solution that re-uses PropertyMock, but has the disadvantage of only allowing setters to be mocked in the context.

with patch.object(SomeClass, 'value', new_callable = PropertyMock, wraps = partial(
      SomeClass.value.__set__, instance)) as value:
   instance.value = 1
value.assert_called_with(1)
self.assertEquals(instance.value, 3)

or

instance = SomeClass(0)
with patch.object(SomeClass, 'value', PropertyMock(
      side_effect = partial(SomeClass.value.__set__, instance)
   )) as value:
   instance.value = 1
value.assert_called_with(1)
self.assertEquals(instance.value, 3)

Suggestion : 2

How do you mock a python property setter when porting it (i.e. calling the original setter)? The most direct way is to access __set__ , but it is read-only for properties, so it doesn't work.,You need to replace the whole object property ; you can't just replace the installer. this means you will need to provide a new object property where the setter is your layout wrapper for the original setter (attribute access property.fset ):,I've used the decorator @property.setter here again ; it returns a new object property with all the attributes of the original property , except that the setter is replaced with what was passed; see How does the @property decorator work?,Here's another solution that reuses PropertyMock but only has the drawback of allowing setters to mock in context.

How do you mock a python property setter when porting it (i.e. calling the original setter)? The most direct way is to access __set__

, but it is read-only for properties, so it doesn't work.

from unittest
import TestCase
from unittest.mock
import patch, PropertyMock

class SomeClass:
   def __init__(self, value):
   self._value = value

@property
def value(self):
   return self._value + 1

@value.setter
def value(self, value):
   self._value = value + 1

class TestSomeClass(TestCase):
   def test_value_setter(self):
   instance = SomeClass(0)
with patch.object(SomeClass.value, '__set__', wraps = SomeClass.value.__set__) as value_setter:
   instance.value = 1
value_setter.assert_called_with(instance, 1)
self.assertEquals(instance.value, 3)

(adsbygoogle = window.adsbygoogle || []).push({});

You need to replace the whole object property

; you can't just replace the installer. this means you will need to provide a new object property

where the setter is your layout wrapper for the original setter (attribute access property.fset

):

setter_mock = Mock(wraps = SomeClass.value.fset)
mock_property = SomeClass.value.setter(setter_mock)
with patch.object(SomeClass, 'value', mock_property):
   instance.value = 1
setter_mock.assert_called_with(instance, 1)

(adsbygoogle = window.adsbygoogle || []).push({});

Here's another solution that reuses PropertyMock

but only has the drawback of allowing setters to mock in context.

with patch.object(SomeClass, 'value', new_callable = PropertyMock, wraps = partial(
      SomeClass.value.__set__, instance)) as value:
   instance.value = 1
value.assert_called_with(1)
self.assertEquals(instance.value, 3)

(adsbygoogle = window.adsbygoogle || []).push({});

or

instance = SomeClass(0)
with patch.object(SomeClass, 'value', PropertyMock(
      side_effect = partial(SomeClass.value.__set__, instance)
   )) as value:
   instance.value = 1
value.assert_called_with(1)
self.assertEquals(instance.value, 3)

(adsbygoogle = window.adsbygoogle || []).push({});

Suggestion : 3

Mock is a flexible mock object intended to replace the use of stubs and test doubles throughout your code. Mocks are callable and create attributes as new mocks when you access them [1]. Accessing the same attribute will always return the same mock. Mocks record how you use them, allowing you to make assertions about what your code has done to them.,The mock argument is the mock object to configure. If None (the default) then a MagicMock will be created for you, with the API limited to methods or attributes available on standard file handles.,unittest.mock is a library for testing in Python. It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used.,Seal will disable the automatic creation of mocks when accessing an attribute of the mock being sealed or any of its attributes that are already mocks recursively.

>>> from unittest.mock
import MagicMock
   >>>
   thing = ProductionClass() >>>
   thing.method = MagicMock(return_value = 3) >>>
   thing.method(3, 4, 5, key = 'value')
3
   >>>
   thing.method.assert_called_with(3, 4, 5, key = 'value')
>>> mock = Mock(side_effect = KeyError('foo')) >>>
   mock()
Traceback(most recent call last):
   ...
   KeyError: 'foo'
>>> values = {
      'a': 1,
      'b': 2,
      'c': 3
   } >>>
   def side_effect(arg):
   ...
   return values[arg]
      ...
      >>>
      mock.side_effect = side_effect >>>
      mock('a'), mock('b'), mock('c')
      (1, 2, 3) >>>
      mock.side_effect = [5, 4, 3, 2, 1] >>>
      mock(), mock(), mock()
      (5, 4, 3)
>>> from unittest.mock
import patch
   >>>
   @patch('module.ClassName2')
   ...@patch('module.ClassName1')
   ...def test(MockClass1, MockClass2):
   ...module.ClassName1()
   ...module.ClassName2()
   ...assert MockClass1 is module.ClassName1
   ...assert MockClass2 is module.ClassName2
   ...assert MockClass1.called
   ...assert MockClass2.called
   ...
   >>>
   test()
>>> with patch.object(ProductionClass, 'method', return_value = None) as mock_method:
   ...thing = ProductionClass()
   ...thing.method(1, 2, 3)
   ...
   >>>
   mock_method.assert_called_once_with(1, 2, 3)
>>> foo = {
      'key': 'value'
   } >>>
   original = foo.copy() >>>
   with patch.dict(foo, {
      'newkey': 'newvalue'
   }, clear = True):
   ...assert foo == {
      'newkey': 'newvalue'
   }
   ...
   >>>
   assert foo == original

Suggestion : 4

return_value: The value returned when the mock is called. By default this is a new Mock (created on first access). See the return_value attribute.,return_value: The value returned when the mock is called. By default this is a new Mock (created on first access). See the return_value attribute. ,If the mock has an explicit return_value set then calls are not passed to the wrapped object and the return_value is returned instead.,Mock objects are callable. The call will return the value set as the return_value attribute. The default return value is a new Mock object; it is created the first time the return value is accessed (either explicitly or by calling the Mock) - but it is stored and the same one returned each time.

>>> from unittest.mock
import MagicMock
   >>>
   thing = ProductionClass() >>>
   thing.method = MagicMock(return_value = 3) >>>
   thing.method(3, 4, 5, key = 'value')
3
   >>>
   thing.method.assert_called_with(3, 4, 5, key = 'value')
>>> mock = Mock(side_effect = KeyError('foo')) >>>
   mock()
Traceback(most recent call last):
   ...
   KeyError: 'foo'
>>> values = {
      'a': 1,
      'b': 2,
      'c': 3
   } >>>
   def side_effect(arg):
   ...
   return values[arg]
      ...
      >>>
      mock.side_effect = side_effect >>>
      mock('a'), mock('b'), mock('c')
      (1, 2, 3) >>>
      mock.side_effect = [5, 4, 3, 2, 1] >>>
      mock(), mock(), mock()
      (5, 4, 3)
>>> from unittest.mock
import patch
   >>>
   @patch('module.ClassName2')
   ...@patch('module.ClassName1')
   ...def test(MockClass1, MockClass2):
   ...module.ClassName1()
   ...module.ClassName2()
   ...assert MockClass1 is module.ClassName1
   ...assert MockClass2 is module.ClassName2
   ...assert MockClass1.called
   ...assert MockClass2.called
   ...
   >>>
   test()
>>> with patch.object(ProductionClass, 'method', return_value = None) as mock_method:
   ...thing = ProductionClass()
   ...thing.method(1, 2, 3)
   ...
   >>>
   mock_method.assert_called_once_with(1, 2, 3)
>>> foo = {
      'key': 'value'
   } >>>
   original = foo.copy() >>>
   with patch.dict(foo, {
      'newkey': 'newvalue'
   }, clear = True):
   ...assert foo == {
      'newkey': 'newvalue'
   }
   ...
   >>>
   assert foo == original