9

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?

Community
  • 1
  • 1
NeilenMarais
  • 2,949
  • 1
  • 25
  • 23

1 Answers1

10

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()]
zwalker
  • 346
  • 5
  • 9