Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Python Mock library to spy on internal method calls

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?

like image 713
NeilenMarais Avatar asked Jan 06 '14 14:01

NeilenMarais


People also ask

How do you mock method calls in Python?

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 .

What is difference between mock and spy?

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.

What is the difference between mock and MagicMock?

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.


1 Answers

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()]
like image 57
zwalker Avatar answered Sep 22 '22 19:09

zwalker