如何用模拟来嘲笑只读属性?

你怎么用模拟来嘲笑一个只读的属性?

我试过了:

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

但问题是,它然后适用于所有类的实例…这打破了我的testing。

你有其他想法吗? 我不想嘲笑完整的对象,只有这个特定的属性。

我认为更好的方法是将Property作为PropertyMock来模拟,而不是直接模拟__get__方法。

这是在文档中声明,searchunittest.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() 

实际上, 文档中的答案是(和往常一样),只是我在跟踪他们的例子时将补丁应用于实例而不是类。

这里是如何做到这一点:

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

在testing套件中:

 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 

可能是一个风格问题,但如果你喜欢装修testing,@詹姆斯卡斯尔菲尔德的答案可以改变为这样的事情:

 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() 

如果你不想testing模拟的属性是否被访问,你可以简单地用预期的return_value补丁。

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