5

I'm trying to attach a spy to a method in a class using the (backported) mock module. That is, I want to create a mock which works like the original method but offers the usual Mock features like call_count, etc.

Here's the code I'm currently using:

import mock

class MyClass(object):
    def my_method(self, arg):
        return arg + 1

def unit_under_test():
    inst = MyClass()
    return inst.my_method(1)

with mock.patch.object(MyClass, 'my_method', autospec=True,
                       side_effect=MyClass.my_method) as spy:
    result = unit_under_test()
    assert result == 2
    assert spy.call_count == 1

That's working nicely. Now I want to use a custom subclass of MagicMock instead. The patch documentation says that this can be done via the new_callable argument. However, new_callable and autospec cannot be used together:

class MyMock(mock.MagicMock):
    pass

with mock.patch.object(MyClass, 'my_method', autospec=True,
                       side_effect=MyClass.my_method,
                       new_callable=MyMock) as spy:
    ...
Traceback (most recent call last):
  File "./mocktest.py", line 19, in <module>
    new_callable=MyMock) as spy:
  File "/var/foo/venv/local/lib/python2.7/site-packages/mock.py", line 1442, in _patch_object
    spec_set, autospec, new_callable, kwargs
  File "/var/foo/venv/local/lib/python2.7/site-packages/mock.py", line 1127, in __init__
    "Cannot use 'autospec' and 'new_callable' together"
ValueError: Cannot use 'autospec' and 'new_callable' together

The problem is that leaving out autospec doesn't work, either, because then self is not passed along to the original method:

with mock.patch.object(MyClass, 'my_method',
                       side_effect=MyClass.my_method,
                       new_callable=MyMock) as spy:
    ...
Traceback (most recent call last):
  File "./mocktest.py", line 20, in <module>
    result = unit_under_test()
  File "./mocktest.py", line 11, in unit_under_test
    return inst.my_method(1)
  File "/var/foo/venv/local/lib/python2.7/site-packages/mock.py", line 955, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "/var/foo/venv/local/lib/python2.7/site-packages/mock.py", line 1018, in _mock_call
    ret_val = effect(*args, **kwargs)
TypeError: unbound method my_method() must be called with MyClass instance as first argument (got int instance instead)

Note that I cannot patch my_method of a MyClass instance instead, since the code I'm testing creates its own MyClass instance (as shown in the example code above).

Florian Brucker
  • 9,621
  • 3
  • 48
  • 81

0 Answers0