I am using the builtin unittest library. I am trying to test a function,in this example a
, which calls function b
. Both of these functions are at the top level of the package and are not class based functions. I have read the unittest documentation about where to patch and have found that you must use the patch against the function (a
) importing the other function (b
)and not patching the function itself (b
), but all the answers and documentation seem to only reference class based functions.
I have the following heirarchy:
mypkg
|- __init__.py
|- a.py
|- b.py
|- test
|- __init__.py
|- test_a.py
top level __init__.py
:
from .a import a
from .b import b
__all__ = ['a','b']
a.py:
import .b import b
def a():
...
functionB({"USERNAME": username, "OTHER": other})
b.py:
def b(**kwargs):
// do stuff with kwargs like calling APIs etc
// This function doesn't return anything
test_a.py:
import unittest
from unittest.mock import patch
from ..a import a
fake_return_value = "heythere"
class TestFunctionA(unittest.TestCase):
@patch('mypkg.a.b', return_value=fake_return_value)
# @patch('mympkg.b') # Doesn't work, does not override the original function
def test_mytest(self, mocked_func):
a()
mocked_func.assert_called_once_with(stuff)
Running the above tests with the patch call that is uncommented leads to the test being ran and the original function being called, not the mock function.
What am I doing wrong here? I didn't think it would be this hard to unit test, I come from unit testing React apps, so this is a little frustrating but I assume user error. All the documentation and googling I've done so far seems that this should work, or at least the patch variant commented out above. Is this because of my package structure and trying to mock functions in the same package or?
Let's look at your top level __init__.py
which contains code executed at import time.
The statement from .a import a
rebinds the name a
from the module a
, to the function a
contained within module a
. As such, all invocations of import mypkg.a
(e.g. the patch in your test module) will return the function a
and not the module. That is why you get the error AttributeError: function a does not have the attribute 'b'
mentioned in your comment on my last answer.
To patch module a
's usage of function b
, your testing code needs to be able to import module a
. There are a few ways you can do this.
from .a import a
in your __init__.py
.
a
via from mypkg import a
or import mypkg.a
a
via from mypkg.a import a
or import mypkg.a.a
a
to something else.