Targetting the right object when using Python mock library's patch

· by Raghu Rajagopalan · Read in about 2 min · (420 words) ·

When you’re writing unit tests, and your class/function under test uses another object, you most likely want replace it with a mock object in your test so you can define it’s behavior. This is where Python standard library’s unittest.mock library comes in along with it’s Mock class and patch functions.

from mock import patch

...

with patch('package.module.Classname') as mockObj:
    # do something with the mock

Tip 1: Figuring out the right namespace

The trouble is that specifying what to mock isn’t always quite straightforward - esp for someone like me who doesn’t fully grok how python looks up objects in namespaces. Struggled today with a couple of tests and finally figured it out - so going to write it it out so that I can come back to it at a later date.

Consider this - you have a.py that’s imported into b.py and you’re writing a test for a function in b.py.

file:a.py
def myfunc():
    # do something
    pass
file: b.py
from a import myfunc

def functionToTest():
    # do something
    # call myfunc
    myfunc()
    # do other stuff
    return

With the from a import x form of import, now myfunc has been imported into the b namespace. We’d like to mock the call to myfunc in our test for functionToTest - so you write patch('b.myfunc')

file: test_b.py
import b

def test_method():
    with patch('b.myfunc') as myfuncMock:
        # set up your mock
        myfuncMock.return_value = 10

        # call your sut.
        b.functionToTest()

On the other hand, let’s say you used the import a form of import in b.py

file: b.py
import a

def functionToTest():
    # do something
    # call myfunc
    a.myfunc()
    # do other stuff
    return

Now in this case, the object to mock is looked up from the a namespace - so that’s what you target in the patch call.

file: test_b.py
import b

def test_method():
    with patch('a.myfunc') as myfuncMock:
        myfuncMock.return_value = 10

        # call your sut.
        b.functionToTest()

Tip 2: Using patch as a decorator - argument order

Patch can be used as a function, class or method decorator. If at a class level then each method gets an extra argument which is the mock passed in. If you patch more than one object, then they’re passed in outside in:

@patch('b.myfunc')  (1)
@patch('b.myotherfunc')
def someMethod(self,
                otherfuncMock, (2)
                myfuncMock):
    # do something here...
1 Notice the order of patch decorators
2 method arguments are the other way in

Given that I have to look this up everytime, I’m pretty sure that the future me is going to like the present me for this!