pythonunit-testingmockingpython-unittestmox

Mock a function which is called when a module is imported


I want to test a module A which uses decorators with arguments. The arguments get evaluated when the module A is loaded. For some of the decorator args, I set the value by calling a function foo in module B.

# A.py
import B

@deco(arg1=B.foo())
def bar():
  ...

When I want to test A, I want to mock B.foo so that the decorator argument is set for my test cases. I think that B.foo must be mocked before A loads B.

In the unit test, as a caller of A, how do I mock B.foo to ensure the mocked version is used when evaluating the decorator arguments in A?


Solution

  • If you want to ensure that the mock is really used, you have to reload module A after patching foo, as bar already had been evaluated with the original foo. You could wrap that in a fixture like this (untested):

    import importlib
    import pytest
    from unittest import mock
    import A
    
    @pytest.fixture
    def mocked_foo():
        with mock.patch('B.foo') as mocked:
            importlib.reload(A)
            yield mocked
    
    def test_bar(mocked_foo):
        ...