I'm using the Python mock module for tests. I want to spy on internal method calls made by a live object. I discovered that the 'wraps' kwarg can be used to set up a mock that spies on method calls to a live object:
Using Python mock to spy on calls to an existing object
but this does not work for internal calls. I want to use this to test that a higher level method calls lower level methods in the correct order.
Given:
class ClassUnderTest(object):
def lower_1(self):
print 'lower_1'
def lower_2(self):
print 'lower_2'
def higher(self):
self.lower_1()
self.lower_2()
I want to be able to test it as
import mock
DUT = ClassUnderTest()
mock_DUT = mock.Mock(wraps=DUT)
# test call
mock_DUT.higher()
# Assert that lower_1 was called before lower_2
assert mock_DUT.mock_calls[1:] = [mock.call.lower_1(), mock.call.lower_2()]
This does not work, since the 'self' parameter is higher() is bound to the original DUT object, and not the mock_DUT spy. Hence only the initial higher() call is logged to mock_calls. Is there a convenient way to perform this kind of assertion using the python mock module?
How do we mock in Python? Mocking in Python is done by using patch to hijack an API function or object creation call. When patch intercepts a call, it returns a MagicMock object by default. By setting properties on the MagicMock object, you can mock the API call to return any value you want or raise an Exception .
Mocks are used to create fully mock or dummy objects. It is mainly used in large test suites. Spies are used for creating partial or half mock objects. Like mock, spies are also used in large test suites.
Mock vs. So what is the difference between them? MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use (e.g. __str__ , __len__ , etc.). Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.
This is sort of like using a Mockito spy in Java. http://docs.mockito.googlecode.com/hg/latest/org/mockito/Spy.html
You can construct a "spy" using the Mock(spec=obj) constructor which will make the __class__
attribute equal to ClassUnderTest where the Mock(wraps=obj) constructor will not. Since in python class methods take the a class instance, the self parameter, as their first parameter, you can call it with a mock as if it were a static method on the class.
import mock
DUT = ClassUnderTest()
spy = mock.Mock(spec=DUT)
# test call
ClassUnderTest.higher(spy)
# Assert that lower_1 was called before lower_2
assert spy.mock_calls == [mock.call.lower_1(), mock.call.lower_2()]
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