在 python Mock 中向 side_effects 添加额外参数

mac*_*acm 2 mocking python-3.x

from unittest.mock import patch

def get_title():
    return 'title'


def get_msg():
    return 'msg'


def do_log(title, msg):
    sys.stderr.write(get_title(),
                     get_msg())
    return


def myfunction():
    title = get_title()
    msg = get_msg()
    do_log(title, msg)


def my_new_do_log(*args, **kwargs):
    '''
    we know, args = title, msg
    But I want add EXTRA arguments, 
    like handler (from caller / from controller)
    '''
    sys.stderr.write(get_title(),
                     get_msg(),
                     handler.get_author_from_handler()
                     )
    # Note: handler is argument from controller!


@patch('do_log')
def controller(handler, mock_do_log):
    mock_do_log.side_effect = my_new_do_log
    myfunction()


if __name__ == '__main__':
    controller(handler)
Run Code Online (Sandbox Code Playgroud)

那么如何将“处理程序”(一个额外的参数)传递给 my_new_do_log 呢?

如果我尝试类似的事情:

mock_do_log.side_effect = my_new_do_log(handler)
Run Code Online (Sandbox Code Playgroud)

我失去了上下文管理器的参数(标题和味精)。是否可以将额外的参数附加到上下文管理器。

Mic*_*ico 7

您可以定义一个新的可调用对象controller()并将其用作副作用。简单而简洁的方法是使用lambda函数:

@patch('do_log')
def controller(handler, mock_do_log):
    mock_do_log.side_effect = lambda *args,**kwargs:my_new_do_log(handler,*args,**kwargs)
    myfunction()
Run Code Online (Sandbox Code Playgroud)

其中,my_new_do_log()签名成为

def my_new_do_log(handler, *args, **kwargs):
    ....
Run Code Online (Sandbox Code Playgroud)

您可以定义一个新的显式函数来执行此操作

@patch('do_log')
def controller(handler, mock_do_log):
    def handler_log(*args,**kwargs):
        my_new_do_log(handler,*args,**kwargs)
    mock_do_log.side_effect = handler_log
    myfunction()
Run Code Online (Sandbox Code Playgroud)

但我的口味是lambda版本。


关于上下文管理器的问题有点困惑:您的示例中没有任何上下文管理器,而只有一个行为类似于上下文管理器的补丁装饰器。无论如何,我认为您可以重复我的建议以考虑您想要的参数数量。