Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does mock ignore the instance/object passed to a mocked out method when it is called?

I have recently noticed that if I mock out a method using mock.patch it doesn't list the instance object passed to the mocked method in the call_args field. Is this by design? Code/output below may better explain what I mean:

#!/usr/bin/env python2

from mock import patch

class Dog(object):
    def bark(self):
        print("Woof woof!")

Dog().bark()

def new_method(*args):
    print("args = %s" % str(args))

Dog.bark = new_method

Dog().bark()

with patch.object(Dog, "bark"):
    d = Dog()
    d.bark()
    print("d.bark was called: %s" % str(d.bark.called))
    print("d.bark was called with args/kwargs: %s" % str(d.bark.call_args))

Output is:

Woof woof!
args = (<__main__.Dog object at 0x7f42c2dbc3d0>,)

# Mocking bit
d.bark was called: True
d.bark was called with args/kwargs: ((), {})

You can see that the instance object is passed to new_method when it replaces bark. But you cannot see it in the call_args of the mocked out method. Isn't this strange? I am using version 1.01 of the python mock library.

like image 747
NaKhaaaaan Avatar asked Sep 06 '15 01:09

NaKhaaaaan


People also ask

Does mock object call real method?

In the given statement the real function kit. getResource() is called which leads to an NPE since function calls on resources are not mocked.

What is the difference between mock and MagicMock?

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.

What does mocker patch do?

The library also provides a function, called patch() , which replaces the real objects in your code with Mock instances. You can use patch() as either a decorator or a context manager, giving you control over the scope in which the object will be mocked.

What is mocking in Pytest?

In pytest , mocking can replace the return value of a function within a function. This is useful for testing the desired function and replacing the return value of a nested function within that desired function we are testing.


1 Answers

By

with patch.object(Dog, "bark"):

You are patching the static instance of Dog.bark method because you are patching Dog class and not a Dog object.

Now the mock method will be called as a static method and not as object method: that means the self attribute will not passed.

If you want create a patch with the same signature of original method you can use autospec=True attribute: in this case the mock method will be an object method instead of a static method.

>>> from mock import patch
>>> with patch.object(Dog, "bark", autospec=True):
...     d = Dog()
...     d.bark()
...     print("d.bark was called with args/kwargs: %s" % str(d.bark.call_args))
... 
<MagicMock name='bark()' id='139848306278672'>
d.bark was called with args/kwargs: call(<Dog object at 0x7f30f89ef390>)
like image 165
Michele d'Amico Avatar answered Sep 29 '22 11:09

Michele d'Amico