6

I want to create a mock method that calls the underlying method being mocked.

I'm imagining something like the following, but I can't find any documentation about the mock object holding a reference to the object being mocked, which I've denoted as [[wrapped_method_foo]] below:

from mock import patch

class Foo(object):
    def __init__(self, state):
        self.state = state
    def foo(self, a):
        print "real foo", a
        return a + self.state

f = Foo(2000)
f.foo(1)

with patch.object(Foo, 'foo', autospec=True) as mock_foo:
    def side_effect(self, a):
        print "mock foo", a
        return mock_foo.[[wrapped_method_foo]](self, a*2)
    mock_foo.side_effect = side_effect

    f.foo(2)
cbare
  • 12,060
  • 8
  • 56
  • 63

2 Answers2

9

The simplest way is to grab your own reference to the original function before patching. Patching can be done on an individual instance of the class:

original_foo = f.foo
with patch.object(f, 'foo') as mock_foo:
    def side_effect(a):
        print "mock foo", a
        return original_foo(a*2)
    mock_foo.side_effect = side_effect

    f.foo(2)

...or by patching the unbound method on the class:

original_foo = Foo.foo
with patch.object(Foo, 'foo', autospec=True) as mock_foo:
    def side_effect(self, a):
        print "mock foo", a
        return original_foo(self, a*2)
    mock_foo.side_effect = side_effect

    f.foo(3)
cbare
  • 12,060
  • 8
  • 56
  • 63
Erin Call
  • 1,764
  • 11
  • 15
  • Thanks Erin. I had to modify slightly to get it to work. But, I'm beginning to doubt whether my original intention to use the mock object this way is a good idea. – cbare Jun 08 '15 at 22:34
3

patch objects have an undocumented temp_original attribute that you can use.

Here is what I usually do in that case:

from __future__ import print_function
import mock

class Foo(object):
    def __init__(self, state):
        self.state = state

    def foo(self, a):
        print("real foo", a)
        return a + self.state


f = Foo(2000)
f.foo(1)

fake_foo = mock.patch.object(Foo, 'foo', autospec=True)
# def side_effect(*args, **kwargs):  # generic version
def side_effect(self, a):
    print("mock foo", a)
    return fake_foo.temp_original(self, a*2)

with fake_foo as mock_foo:
    mock_foo.side_effect = side_effect

    assert f.foo(2) == 2004

I'm using this when I only use mock to assert that functions where called during tests

Romuald Brunet
  • 5,595
  • 4
  • 38
  • 34
  • Why not use the documented `mock.DEFAULT` attribute? https://docs.python.org/3/library/unittest.mock.html#unittest.mock.DEFAULT – asmaier Mar 27 '20 at 14:43
  • @asmaier I wasn't aware of it. I guess the docs are confusing? The `DEFAULT` value seems to be … default value of the various methods. I made a few tests and was unable to do what you're implying – Romuald Brunet Mar 28 '20 at 16:08