Python Mocking a function from an imported module
Solution 1
When you are using the patch
decorator from the unittest.mock
package you are patching it in the namespace that is under test (in this case app.mocking.get_user_name
), not the namespace the function is imported from (in this case app.my_module.get_user_name
).
To do what you describe with @patch
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.
Solution 2
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')
Related videos on Youtube
nsfyn55
I've been writing code since the mid 90's, for money since the early 2000's. I have worked for several notable companies including RedHat, Navteq/Nokia, OpenX plus a number of not so notable startups. My first language was C++, but my primary professional experience is in Java, Scala, Python, and PHP. I am a devops enthusiast currently obsessed with Arch linux and LFS. I currently work for a Linode Career Stuff: http://careers.stackoverflow.com/nsfyn55 nsfyn55 at gee male
Updated on December 16, 2021Comments
-
nsfyn55 over 2 years
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?-
nsfyn55 about 11 yearsI 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 about 11 yearsthis gets to my problem.
get_user_name
is in a different module thantest_method
. Is there a way to mock something in a sub_module? I fixed it in an ugly way below. -
Matti John about 11 yearsIt doesn't matter that
get_user_name
is in a different module thantest_method
since you are importing the function intoapp.mocking
they are in the same namespace. -
Mike G over 10 yearsWhere did test_patch come from, what is it exactly?
-
Matti John over 10 yearstest_patch is passed in by the patch decorator and is the mocked get_user_name object (i.e. an instance of the MagicMock class). It might be clearer if it was named something like
get_user_name_patch
. -
nsfyn55 almost 9 yearsThis is sort of immaterial to the posed question. Whether you use
patch
as a decorator or context manager is specific to the use case. For instance you can usepatch
as a decorator to mock a value for all tests in anxunit
orpytest
class while in other cases its useful to have the fine grained control afforded by the context manager. -
Aditya over 6 yearsHow are you referencing test_method? It will result in error, NameError: global name 'test_method' is not defined
-
Matti John over 6 years
test_method
is just a placeholder for the function being tested, in the question it's imported. I have added the import to match the example code in the question. -
Eats Indigo over 6 yearsThank you this was very helpful. It had me thrown for a while that you only need to stub the imported callable
-
Kurt Bourbaki over 5 yearsI think this section should be moved on the very top of the docs.
-
kellen almost 5 yearsThank you very much! Despite having read the "Where to patch" section of the docs, I didn't fully grok it until I read your answer.
-
Gurce about 3 yearsOne little caveat that I tripped over just now was that the "from mock import patch" line must be the first line. If you import test_method first, and then import patch, it won't work. Just wanted to highlight that.