【问题标题】:python mock property setter while wrapping it包装时的python模拟属性设置器
【发布时间】:2015-03-07 23:49:19
【问题描述】:

如何在包装 python 属性设置器时模拟它(即调用原始设置器)?最直接的方法是访问__set__,但它对属性是只读的,所以不起作用。

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)

文档中还有new_callable=PropertyMock,我尝试将其与wrap 结合使用,但还没有使用。

【问题讨论】:

  • 哦,太好了,您注意到 getter 将在您的测试用例中自己返回 3。 :-P
  • 是的,我在运行代码时意识到 :)

标签: python properties mocking unit-testing


【解决方案1】:

您需要替换整个property 对象;你不能简单地更换二传手。这意味着您需要提供一个新的 property 对象,其中 setter 是原始 setter 的模拟包装器(通过 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)

我在这里重用了@property.setter 装饰器;它返回一个新的property 对象,该对象具有原始property 的所有属性,除了setter 被传入的任何内容替换;见How does the @property decorator work?

【讨论】:

  • 这可以用来修补内存中类的属性吗?据我了解,所有这些示例都会修补实例......不是吗?
  • @yucer:我的回答是模拟类的属性,而不是该类的特定实例。
【解决方案2】:

这是另一个重用 PropertyMock 的解决方案,但缺点是只允许在上下文中模拟设置器。

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)

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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-27
    • 2017-11-25
    相关资源
    最近更新 更多