我们如何确保Mock.call_args_list中的调用包含调用Mock对象时参数处于相同状态的调用?

时间:2016-10-25 19:23:13

标签: python unit-testing mocking

from mock import Mock
j = []
u = Mock()
u(j)
# At this point u.call_args_list == [call([])]
print u.call_args_list
j.append(100)
# At this point u.call_args_list == [call([100])], but I expect it to be [call([])], since it was never called when j had a value of 100 in it
print u.call_args_list

我的问题是如何确保u.call_args_list中的调用在调用模拟时包含所有对象的状态,而不是在检查模拟的参数时?

我目前正在使用mock==1.0.1

1 个答案:

答案 0 :(得分:3)

这在文档部分26.6.3.7. Coping with mutable arguments中讨论。

不幸的是,他们真的没有任何优雅的解决方案!建议的解决方法是使用side_effect从可变参数复制元素。

  

如果为mock提供side_effect函数,则将使用与mock相同的args调用side_effect。这使我们有机会复制参数并将其存储以供以后断言。

在我看来,实施起来有些混乱。如果您需要多个地方的功能,您可能更喜欢子类Mock并直接添加功能:

from copy import deepcopy

class CopyingMock(MagicMock):
    def __call__(self, *args, **kwargs):
        args = deepcopy(args)
        kwargs = deepcopy(kwargs)
        return super(CopyingMock, self).__call__(*args, **kwargs)

2017 :现在可以在第三方发布(pip install copyingmock)中使用。

>>> from copyingmock import CopyingMock
>>> mock = CopyingMock()
>>> list_ = [1,2]
>>> mock(list_)
<CopyingMock name='mock()' id='4366094008'>
>>> list_.append(3)
>>> mock.assert_called_once_with([1,2])
>>> mock.assert_called_once_with(list_)

AssertionError: Expected call: mock([1, 2, 3])
Actual call: mock([1, 2])