Mocking Functions Using Python Mock
Solution 1:
I think I have a workaround, though it's still not quite clear on how to solve the general case
In mymodule
, if I replace
from util import get_content
class MyObj:
def func():
get_content()
with
import util
class MyObj:
def func():
util.get_content()
The Mock
seems to get invoked. It looks like the namespaces need to match (which makes sense). However, the weird thing is that I would expect
import mymodule
mymodule.get_content = mock.Mock(return_value="mocked stuff")
to do the trick in the original case where I am using the from/import syntax (which now pulls in get_content
into mymodule
). But this still refers to the unmocked get_content
.
Turns out the namespace matters - just need to keep that in mind when writing your code.
Solution 2:
The general case would be to use patch
from mock
. Consider the following:
utils.py
def get_content():
return 'stuff'
mymodule.py
from util import get_content
class MyClass(object):
def func(self):
return get_content()
test.py
import unittest
from mock import patch
from mymodule import MyClass
class Test(unittest.TestCase):
@patch('mymodule.get_content')
def test_func(self, get_content_mock):
get_content_mock.return_value = 'mocked stuff'
my_class = MyClass()
self.assertEqual(my_class.func(), 'mocked stuff')
self.assertEqual(get_content_mock.call_count, 1)
get_content_mock.assert_called_once()
Note how get_content
is mocked, it is not util.get_content
, rather mymodule.get_content
since we are using it in mymodule
.
Above has been tested with mock v2.0.0, nosetests v1.3.7 and python v2.7.9.
Solution 3:
You have to patch the function where it is being used. In your case that would be in the mymodule module.
import mymodule
>>> mymodule.get_content = Mock(return_value="mocked stuff")
>>> m = mymodule.MyObj()
>>> m.func()
"mocked stuff"
There is a reference in the docs here: http://docs.python.org/dev/library/unittest.mock.html#where-to-patch
Solution 4:
Let's assume you're creating your mock inside module foobar
:
import util, mock
util.get_content = mock.Mock(return_value="mocked stuff")
If you import mymodule
and call util.get_content
without first importing foobar
, your mock will not be installed:
import util
def func()
print util.get_content()
func()
"stuff"
Instead:
import util
import foobar # substitutes the mock
def func():
print util.get_content()
func()
"mocked stuff"
Note that foobar
can be imported from anywhere (module A imports B which imports foobar) as long as foobar
is evaluated before util.get_content
is called.