如何用模拟来嘲笑只读属性?
你怎么用模拟来嘲笑一个只读的属性?
我试过了:
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()): ...