How to mock a readonly property with mock?
I think the better way is to mock the property as PropertyMock
, rather than to mock the __get__
method directly.
It is stated in the documentation, search for unittest.mock.PropertyMock
:A mock intended to be used as a property, or other descriptor, on a class. PropertyMock
provides __get__
and __set__
methods so you can specify a return value when it is fetched.
Here is how:
class MyClass: @property def last_transaction(self): # an expensive and complicated DB query here passdef 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()
Actually, the answer was (as usual) in the documentation, it's just that I was applying the patch to the instance instead of the class when I followed their example.
Here is how to do it:
class MyClass: @property def last_transaction(self): # an expensive and complicated DB query here pass
In the test suite:
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
Probably a matter of style but in case you prefer decorators in tests, @jamescastlefield's answer could be changed to something like this:
class MyClass: @property def last_transaction(self): # an expensive and complicated DB query here passclass Test(unittest.TestCase): @mock.patch('MyClass.last_transaction', new_callable=PropertyMock) def test(self, mock_last_transaction): mock_last_transaction.return_value = Transaction() myclass = MyClass() print myclass.last_transaction mock_last_transaction.assert_called_once_with()