python mocked function not called

Viewed 2621

I'm testing python code (A django 3.0.5 project although I don't think it's relevant), but I can't get the functions of my mocked objects to be called. Here is my code:

**myproject.mypackage.myhelpers**


def get_dict():
    return dict()

**myproject.mypackage.mythings**

from .myhelpers import get_dict


def use_dict():
    the_dict = get_dict()
    pass
    return


**myproject.tests.test_mythings**

from ..mypackage import mythings
import unittest
import unittest.mock as mock


class MyThingsTests(unittest.TestCase):

    @mock.patch('myproject.mypackage.myhelpers')
    def test_using_dict(self, mock_myhelpers):
        test_dict = {
            "hi": "foo",
            "there": "bar",
            "sir": "foobar"
        }

        mock_myhelpers.get_dict.return_value = test_dict

        mythings.use_dict()

        mock_myhelpers.get_dict.assert_called_once()

However in the end the test fails with error:

AssertionError: Expected 'get_dict' to have been called once. Called 0 times

2 Answers

Try this instead:

@mock.patch('myproject.mypackage.mythings.get_dict')
def test_using_dict(self, mock_get_dict):
    test_dict = {
        "hi": "foo",
        "there": "bar",
        "sir": "foobar"
    }

    mock_get_dict.return_value = test_dict

The Where to patch section of the docs explains it a bit.

From how I understand it, myproject.mypackage.mythings will already have imported the "real" get_dict before you do the patch. So if you patch it like @mock.patch('myproject.mypackage.myhelpers'), only the myhelpers module will "know" that it is patched. The mythings module will still have the reference to the real get_dict.

I think an alternative to the way of patching I did above, is to change how you import get_dict instead. Instead of importing get_dict directly, just import myhelpers and use get_dict as myhelpers.get_dict. Then you should be able to keep your way of patching the same because get_dict will be looked up from the myhelpers which would have the patched method.

Solution 1

  • replace myproject.mypackage.myhelpers with myproject.mypackage.mythings
# @mock.patch('myproject.mypackage.myhelpers')
@mock.patch('myproject.mypackage.mythings.get_dict')
def test_using_dict(self, mock_get_dict):
    test_dict = {
        "hi": "foo",
        "there": "bar",
        "sir": "foobar"
    }

    mock_get_dict.return_value = test_dict

Solution 2

  • replace from .myhelpers import get_dict with import .myhelpers as helpers
**myproject.mypackage.mythings**

# from .myhelpers import get_dict
import .myhelpers as helpers

def use_dict():
    the_dict = helpers.get_dict()
    pass
    return

Summary

  • solution 1 is better since it won't bother you to update the import style in all your .py files
Related