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

Add extra arguments to side_effects in python Mock

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)

那么如何将 "handler"(一个额外的参数)传递给 my_new_do_log?

如果我尝试这样的事情:

mock_do_log.side_effect = my_new_do_log(handler)

我丢失了上下文管理器的参数(标题和消息)。是否可以向上下文管理器附加额外的参数。

您可以在 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()

其中 my_new_do_log() 签名变为

def my_new_do_log(handler, *args, **kwargs):
    ....

您可以定义一个新的显式函数来完成它

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

但我喜欢 lambda 版本。


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