154
votes

I want to understand how to @patch a function from an imported module.

This is where I am so far.

app/mocking.py:

from app.my_module import get_user_name

def test_method():
  return get_user_name()

if __name__ == "__main__":
  print "Starting Program..."
  test_method()

app/my_module/__init__.py:

def get_user_name():
  return "Unmocked User"

test/mock-test.py:

import unittest
from app.mocking import test_method 

def mock_get_user():
  return "Mocked This Silly"

@patch('app.my_module.get_user_name')
class MockingTestTestCase(unittest.TestCase):

  def test_mock_stubs(self, mock_method):
    mock_method.return_value = 'Mocked This Silly')
    ret = test_method()
    self.assertEqual(ret, 'Mocked This Silly')

if __name__ == '__main__':
  unittest.main()

This does not work as I would expect. The "patched" module simply returns the unmocked value of get_user_name. How do I mock methods from other packages that I am importing into a namespace under test?

2
The question is about "mocking best practices" or whether or not what you are doing makes sense? Regarding the first I'd say to use a mocking library such as Mock, which is included in python3.3+ as unittest.mock.Bakuriu
I am asking if I am going about this right. I looked at Mock, but I don't see a way to solve this particular problem. Is there a way to recreate what I did above in Mock?nsfyn55

2 Answers

203
votes

When you are using the patch decorator from the unittest.mock package you are not patching the namespace the module is imported from (in this case app.my_module.get_user_name) you are patching it in the namespace under test app.mocking.get_user_name.

To do the above with Mock try something like the below:

from mock import patch
from app.mocking import test_method 

class MockingTestTestCase(unittest.TestCase):

    @patch('app.mocking.get_user_name')
    def test_mock_stubs(self, test_patch):
        test_patch.return_value = 'Mocked This Silly'
        ret = test_method()
        self.assertEqual(ret, 'Mocked This Silly')

The standard library documentation includes a useful section describing this.

18
votes

While Matti John's answer solves your issue (and helped me too, thanks!), I would, however, suggest localizing the replacement of the original 'get_user_name' function with the mocked one. This will allow you to control when the function is replaced and when it isn't. Also, this will allow you to make several replacements in the same test. In order to do so, use the 'with' statment in a pretty simillar manner:

from mock import patch

class MockingTestTestCase(unittest.TestCase):

    def test_mock_stubs(self):
        with patch('app.mocking.get_user_name', return_value = 'Mocked This Silly'):
            ret = test_method()
            self.assertEqual(ret, 'Mocked This Silly')