How to mock using patch relative paths?
Building on the accepted answer, I believe that this is the cleanest way to achieve desired goal:
from mock import patch
from .. import monkey
@patch(monkey.__name__+'.ook', Mock(return_value=None))
def test_run_ook (self, mock_ook):
self.assertIsNone(monkey.ook())
mock_ook.run.assert_called_once_with('')
From what I gather, with mock, you need to provide a dotted name when patching. Luckily, every module has access to a special module-level variable __name__
which contains the module's name. Using this, if you want to patch variables local to your module, you should be able to do something like the following:
import mock
import unittest
ook = lambda: "the ook"
class OokTest(unittest.TestCase):
def test_ook(self):
with mock.patch(__name__ + '.ook', return_value=None):
self.assertIsNone(ook())
self.assertEquals(ook(), "the ook")
# the patch decorator should work the same way, I just tend to use the
# context manager out of personal preference
@mock.patch(__name__ + '.ook', return_value=None)
def test_ook_2(self, mock_ook):
self.assertIsNone(ook())
Assuming you've saved that file as quicktest.py
, the unit tests give this result:
$ python -m unittest quicktest
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
And of course, from a.b import c
gives you a plain variable c
in your package, so this same mechanism should work.
Not sure if this is the best way (or even recommended), but one way is to use something like:
from mock import patch,
from ..monkey import ook
[...]
package_base = __package__.rsplit('.', 1)[0]
@patch('{0}.monkey.ook'.format(package_base), Mock(return_value=None))
def test_run_ook (self, mock_ook):
self.assertIsNone(ook())
mock_ook.run.assert_called_once_with('')
I used Dan Passaro's solution till I came across this one using patch.object
– which looks even better to me:
from unittest.mock import patch,
from .. import monkey
[...]
@patch.object(monkey, 'ook', Mock(return_value=None))
def test_run_ook (self, mock_ook):
self.assertIsNone(monkey.ook())
mock_ook.run.assert_called_once_with('')
Advantages:
- No need for the boilerplate code that is
__name__ + '.object_to_be_mocked'
- All dependencies of the test case are clearly stated at the beginning of the file as
import
statements. - In cases where the dotted name of the object you're trying to mock out is longer (say "amazon.jungle.monkey.ook") and you therefore write
@patch.object(amazon.jungle.monkey, 'ook', …)
, your IDE's static code analysis can make sure that at leastamazon.jungle.monkey
is a valid variable since you didn't write the whole thing as a string'amazon.jungle.monkey.ook'
.
Disadvantages:
- You cannot do
from ..monkey import ook
but need to dofrom .. import monkey
and accessook
throughmonkey
, i.e.monkey.ook
. In cases where I need to write this often I will addook = monkey.ook
to the beginning of my tests for convenience. (Or even to the import statements in case I never need to mock out this particular property ofmonkey
.)