How to mock a readonly property with mock?
Solution 1:
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
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()
Solution 2:
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
Solution 3:
If the object whose property you want to override is a mock object, you don't have to use patch
.
Instead, can create a PropertyMock
and then override the property on the type of the mock. For example, to override mock_rows.pages
property to return (mock_page, mock_page,)
:
mock_page = mock.create_autospec(reader.ReadRowsPage)
# TODO: set up mock_page.
mock_pages = mock.PropertyMock(return_value=(mock_page, mock_page,))
type(mock_rows).pages = mock_pages