Search code examples
pythonmonkeypatching

Mock return value of decorator on method under test


As the title says, I'm having a little trouble trying to check that my function under test is decorated with the correct decorator for one, and secondly the right parameters.

Method under test

@command_wrapper.command('string1', 'string2')
def function_under_test():
    return some_other_function();

Unit test

@patch("command_wrapper.command")
def test_function_under_test(self, mock_command_wrapper)
    * Do some testing *

Decorator: command_wrapper.py

def command(string1, string2):
    cmd_decorator(func):
        @wraps(func)
        def func_wrapper():
            * Do some code *
    return func_wrapper
return cmd_decorator

However when the test runs, its clearly executing the decorator without having mocked it. I'm new to Python so I'm not even sure if this is possible, or whether this is the right approach.


Solution

  • Decorators are run at module import time, so you need to patch it when it is being imported. You can do this by force reloading the module, explained here, and again after its unpatched to revert it.

    e.g.:

    #python3.4+ only:
    from importlib import reload
    # python 3.X:
    # from imp import reload
    # python2 reload is built-in
    
    import module_under_test
    
    def test()
        try:
            with patch("command_wrapper.command") as mock_wrapper:
                # make decorator return function unchanged
                mock_wrapper.return_value.side_effect = lambda func: func
                reload(module_under_test)
                ** test stuff **
        finally:
            reload(module_under_test)
    

    This is a bit hacky, probably better to find another way to test, but I think it will work.