How do you mock a readonly property with mock?
I tried:
setattr(obj.__class__, 'property_to_be_mocked', mock.Mock())
but the issue is that it then applies to all instances of the class... which breaks my tests.
Do you have any other idea? I don't want to mock the full object, only this specific property.
you can set up Foo (a read-only property) like this: var stub = new Mock<MyAbstraction>(); stub. SetupGet(x => x. Foo).
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.
You can set the mock object property to the value returned by the mock object method. To achieve this, specify separate behaviors for the method and the property. You can specify one behavior at a time. For more information about mock object behavior, see Specify Mock Object Behavior.
Mock objects allow you to mimic the behavior of classes and interfaces, letting the code in the test interact with them as if they were real. This isolates the code you're testing, ensuring that it works on its own and that no other code will make the tests fail.
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()
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With