I am unittest
ing code which contains a method that does a local import.
def function_under_test():
import unknown.dependency
(I'm not using an import at the top of the .py
file because it may or may not be present when the function is called.)
Mocking unknown.dependency
in the usual way only works if it can be found somewhere in sys.path
. Otherwise, the call to patch
fails (it refuses to mock something it cannot look at):
with mock.patch('unknown.dependency'):
function_under_test()
>>> ImportError: No module named 'unknown'
The docs suggest that I should patch to the namespace where the module is used -- in this case, function_under_test
. However, when that namespace is a function, this doesn't cut it. The call to patch
succeeds, but the actual import statement is still referencing the original, non-existing unknown
module, which cannot be found.
with mock.patch('method_under_test.unknown'):
print("fails")
>>> ImportError: No module named 'unknown'
So, how do I replace the dependency module with a mock, if the module itself does not exist and it is imported from a function?
To mock the return value of an imported function in Jest, you have to either call mockReturnValue or mockImplementation on a Jest mock function and then specify the return value.
Rather than hacking on top of Python's import machinery, you can simply add the mocked module into sys. path , and have Python prefer it over the original module. Now, when the test suite is run, the mocked-lib subdirectory is prepended into sys. path and import A uses B from mocked-lib .
There are two ways to mock functions: Either by creating a mock function to use in test code, or writing a manual mock to override a module dependency.
The easy way out is to move the import statement into a separate function.
def get_dependency():
import unknown.dependency
return unknown.dependency
def function_under_test():
module = get_dependency()
# use module
That makes it easy to mock out only that 'helper' function. This has the disadvantage that it requires a change to the code under test. It does work though:
with mock.patch('get_dependency'):
function_under_test()
As described here, you can add the mocked module straight to sys.modules
so that Python can find it regardless of whether it's present in sys.path
or not.
with mock.patch.dict('sys.modules', unknown=mock.MagicMock()):
function_under_test()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With