Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I mock a module that is imported from a function and not present in sys.path? [duplicate]

I am unittesting 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?

like image 225
florisla Avatar asked Jan 26 '17 12:01

florisla


People also ask

How do you mock an imported 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.

Can you mock an import in Python?

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 .

How do you mock a particular function in Jest?

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.


1 Answers

Mock the import only

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()

Mock the module

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()
like image 66
florisla Avatar answered Oct 27 '22 04:10

florisla