2012-08-06 62 views
47

你如何模仿mock只讀屬性?如何用模擬模擬只讀屬性?

我想:

setattr(obj.__class__, 'property_to_be_mocked', mock.Mock()) 

但問題是,它則適用於類...打破我的測試中的所有實例。

你有什麼想法嗎?我不想嘲笑完整的對象,只有這個特定的屬性。

回答

37

實際上,答案是(和往常一樣)在documentation中,只是當我按照他們的例子將補丁應用於實例而不是類時。

這裏是如何做到這一點:

class MyClass: 
    @property 
    def last_transaction(self): 
     # an expensive and complicated DB query here 
     pass 

在測試套件:

def test(): 
    # Make sure you patch on MyClass, not on a MyClass instance, otherwise 
    # you'll get an AttributeError, because mock is using settattr and 
    # last_transaction is a readonly property so there's no setter. 
    with mock.patch(MyClass, 'last_transaction') as mock_last_transaction: 
     mock_last_transaction.__get__ = mock.Mock(return_value=Transaction()) 
     myclass = MyClass() 
     print myclass.last_transaction 
+6

人應該用其他的例子。 'mock.PropertyMock'是實現它的方法! – vitiral 2016-09-06 19:21:02

73

我認爲更好的辦法是嘲笑財產PropertyMock,而不是嘲笑__get__方法直。

它在documentation中說明,搜索unittest.mock.PropertyMock: 一個模擬打算用作一個類的屬性或其他描述符。 PropertyMock提供了__get____set__方法,因此您可以在提取時指定返回值。

方法如下:

class MyClass: 
    @property 
    def last_transaction(self): 
     # an expensive and complicated DB query here 
     pass 

def test(unittest.TestCase): 
    with mock.patch('MyClass.last_transaction', new_callable=PropertyMock) as mock_last_transaction: 
     mock_last_transaction.return_value = Transaction() 
     myclass = MyClass() 
     print myclass.last_transaction 
     mock_last_transaction.assert_called_once_with() 
+0

我不得不模擬一個以'@ property'裝飾的類方法。當其他答案(以及其他許多問題的其他答案)沒有答案時,這個答案對我有用。 – AlanSE 2016-05-19 20:32:04

+2

這是它應該完成的方式。我希望有一種方法來移動「接受」的答案 – vitiral 2016-09-06 19:20:38

+1

我發現包括上下文管理器調用中的返回值稍微更清晰: ''' with mock.patch('MyClass.last_transaction',new_callable = PropertyMock ,return_value = Transaction()): ... ''' – wodow 2017-06-30 17:38:02

3

大概的風格,但如果你喜歡裝飾在測試中,@ jamescastlefield的answer的事情可以改變的東西是這樣的:

class MyClass: 
    @property 
    def last_transaction(self): 
     # an expensive and complicated DB query here 
     pass 

class Test(unittest.TestCase): 
    @mock.patch('MyClass.last_transaction', new_callable=PropertyMock) 
    def test(mock_last_transaction): 
     mock_last_transaction.return_value = Transaction() 
     myclass = MyClass() 
     print myclass.last_transaction 
     mock_last_transaction.assert_called_once_with() 
0

如果你不您不想測試是否訪問了嘲弄的財產,您只需使用預期的return_value即可對其進行修補。

with mock.patch(MyClass, 'last_transaction', Transaction()): 
    ...