2012-08-15 62 views
6

嵌套屬性我有一個函數調用返回一個對象:懲戒故作

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嵌套的屬性?

+0

這很可能是某些事情留他們的方式。結束使用真實的東西,而不是模擬。 – Oleksiy 2012-09-19 00:40:47

回答

10

替換模擬對象的屬性,調用你所期望的:

>> 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' 

這可以讓你嘲諷,同時定義一個特定值的全部力量。

+0

r2是r_original類的實例嗎? – Oleksiy 2012-12-17 20:20:14

+0

不,這是一個MagicMock對象。 – dbn 2012-12-17 20:30:02

3

如果你想在其他地方露出原有的特性,你可以定義一個包裝類:

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'