【问题标题】:Mocking nested properties with mock用 mock 模拟嵌套属性
【发布时间】:2012-08-12 07:37:07
【问题描述】:

我有一个返回对象的函数调用:

r = Foo(x,y)

r 有一组丰富的嵌套属性。例如,我可以访问r.prop_a.prop_b.prop_c。我想模拟Foo,从而修改r 的特定叶属性,即r.prop_a.prop_b.prop_c 返回我控制下的值:

>> r = Foo(x,y)
>> r.prop_a.prop_b.prop_c
'fish'
>> # some mock magic patching of Foo is taking place here
>> r = Foo(x,y)
>> r.prop_a.prop_b.prop_c
'my_fish'

我不太关心中间属性。

有没有一种优雅的方法可以用 mock 模拟嵌套属性?

【问题讨论】:

  • 很可能某些事情保持原样。最终使用真实的东西而不是模拟。

标签: python unit-testing properties mocking nested


【解决方案1】:

按照你的预期替换模拟对象的属性调用:

>> r1 = r_original(x, y)
>> r1.prop_a.prop_b.prop_c
'fish'

>> returner = mock.MagicMock()
>> returner.prop_a.prop_b.prop_c = 'fish'
>> r_mocked = mock.MagicMock(spec_set=r_original, return_value=returner)
>> r2 = r_mocked(x, y)
>> r2.prop_a.prop_b
MagicMock name='returner.prop_a.prop_b' id='87412560'>
>> r2.prop_a.prop_b.prop_c
'fish'

这允许您在定义特定值的同时充分发挥模拟功能。

【讨论】:

  • r2 是 r_original 类的实例吗?
  • 不,它是一个 MagicMock 对象。
【解决方案2】:

如果你想在别处暴露原始属性,你可以定义一个包装类:

class OverrideAttributePath(object):
    """A proxy class where we override a specific attribute path with the
    value given. For any other attribute path, we just return
    attributes on the wrapped object.

    """
    def __init__(self, thing, path, value):
        self._thing = thing
        self._path = path
        self._value = value

    def __dir__(self):
        return dir(self._thing)

    def __len__(self):
        return len(self._thing)

    def __getitem__(self, index):
        if self._path == [index]:
            return self._value
        elif self._path[0] == index:
            return OverrideAttributePath(
                self._thing[index], self._path[1:], self._value)
        else:
            return self._thing[index]

    def __getattr__(self, key):
        if self._path == [key]:
            return self._value
        elif self._path[0] == key:
            return OverrideAttributePath(
                getattr(self._thing, key), self._path[1:], self._value)
        else:
            return getattr(self._thing, key)

那么用法如下:

>>> r = Foo(x,y)
>>> r2 = OverrideAttributePath(r, ['prop_a', 'prop_b', 'prop_c'], 'my_fish')
>>> r2.prop_a.prop_b.prop_c
'my_fish'

【讨论】:

    猜你喜欢
    • 2019-09-23
    • 2021-07-15
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多