11

I have recently started using the mock framework in python. It seems that if I patch a function, the actual code is not called - which means that the database changes etc that this actual function does is not implemented. I have been trying to go around it by calling the function before hand and storing the return value and passing it as arg in patch(), but is there a better way to do it? Ideally, I would want a code that works as a silent observer and i can simply ask it if a certain observed function was called or not, how many times, and with what arguments

My current code

return_val = funct()

# C: Now call me again and assert that these intensive computation functions are not called but taken from cache
with patch('funct', return_value=return_val) as mock_task:

    me_response = self.client.get(me_url, format='json')    #should fetch from cache
    assert not mock_task.called
dowjones123
  • 3,695
  • 5
  • 40
  • 83
  • 2
    You don't mock the function you are testing. You mock the methods inside the function you are testing, so you can test its expected behaviour. So, if you have a method `foo` you want to test, and inside `foo` you are making a call to some method `bar`, you want to mock `bar`. – idjaw Apr 19 '16 at 11:58

2 Answers2

11

To mock a method called, you should use the wraps keyword. Consider the following:

class Foo(object):

    def do_thing(self, a):
        print("A: %s" % a)
        self._do_private_thing(a)

    def _do_private_thing(self, a):
        print("PRIVATE STUFF HAPPENING.")
        print("A: %s" % a)

Then In your test you would have something like:

import mock
a = Foo()
with mock.patch.object(a, '_do_private_thing', wraps=a._do_private_thing) as private_mock:
    a.do_thing("lol")
    private_mock.assert_called_with("lol")

Hope this helps.

Jerther
  • 5,558
  • 8
  • 40
  • 59
loganasherjones
  • 1,012
  • 2
  • 11
  • 19
5

You could set the Mock#side_effect attribute to your original function.

orig = funct
funct = Mock(side_effect=orig)

I do find loganasherjones' answer more elegant.

Just adding another possibility for those who may need it.

l__flex__l
  • 1,388
  • 1
  • 16
  • 22
  • What if the function you are mocking, orig in this case, has input arguments? How do you use the arguments that the actual code is calling the function with and use it as input to the side_effect (and the original patch function if necessary)? – cmoses Oct 11 '19 at 15:30
  • The arguments will be passed on to the original function. Passing arguments incorrectly will cause an exception. It is just like having the original function with the added features of mock. Try it out in ipython. – l__flex__l Oct 22 '19 at 16:29