Python模拟方法调用参数显示列表的最后一个状态

Bab*_*bar 7 python unit-testing mocking

我有一个函数,它将列表作为参数.多次调用该函数,并且每次更新某些列表值时.我用来捕获调用参数的模拟对象总是在列表中显示所有调用参数的最新值.以下代码显示了该问题.

from mock import MagicMock

def multiple_calls_test():
    m = MagicMock()
    params = [0, 'some_fixed_value', 'some_fixed_value']
    for i in xrange(1,10):
        params[0] = i
        m(params)
    for args in m.call_args_list:
        print args[0][0]

multiple_calls_test()
Run Code Online (Sandbox Code Playgroud)

这是输出,注意所有调用都有9作为第一个列表元素.

[9, 'some_fixed_value', 'some_fixed_value']
[9, 'some_fixed_value', 'some_fixed_value']
[9, 'some_fixed_value', 'some_fixed_value']
[9, 'some_fixed_value', 'some_fixed_value']
[9, 'some_fixed_value', 'some_fixed_value']
[9, 'some_fixed_value', 'some_fixed_value']
[9, 'some_fixed_value', 'some_fixed_value']
[9, 'some_fixed_value', 'some_fixed_value']
[9, 'some_fixed_value', 'some_fixed_value']
Run Code Online (Sandbox Code Playgroud)

有没有办法强制模拟对象复制list参数而不是保持对实际列表的引用?或者为每个方法执行断言正确值的其他方法?谢谢.

rob*_*cox 8

不幸的是,这看起来是mock库的一个缺点,从查看代码看,如果不修补模拟库本身,这看起来是不可能的.但是,看起来有一种相当轻量级的方法来获得您正在寻找的效果:

import copy
from mock import MagicMock


class CopyArgsMagicMock(MagicMock):
    """
    Overrides MagicMock so that we store copies of arguments passed into calls to the
    mock object, instead of storing references to the original argument objects.
    """

    def _mock_call(_mock_self, *args, **kwargs):
        args_copy = copy.deepcopy(args)
        kwargs_copy = copy.deepcopy(kwargs)
        return super(CopyArgsMagicMock, self)._mock_call(*args_copy, **kwargs_copy)
Run Code Online (Sandbox Code Playgroud)

然后(陈述显而易见的)简单地MagicMock用a 代替你,CopyArgsMagicMock你应该看到所需的行为.

请注意,这仅针对所提供的用例进行了测试,因此这可能不是解决问题的完整而可靠的解决方案,但希望它证明是有用的.