Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a readonly property with mock?

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.

like image 512
charlax Avatar asked Aug 06 '12 21:08

charlax


People also ask

How do I mock a read only property?

you can set up Foo (a read-only property) like this: var stub = new Mock<MyAbstraction>(); stub. SetupGet(x => x. Foo).

How do you mock a property in Python?

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.

How do you set a mock object property?

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.

What can be mocked with MOQ?

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.


2 Answers

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() 
like image 160
jamescastlefield Avatar answered Sep 28 '22 09:09

jamescastlefield


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 
like image 20
charlax Avatar answered Sep 28 '22 10:09

charlax