Python模拟方法调用参数显示列表的最后状态
我有一个以列表为参数的函数。该函数被多次调用,并且每次更新某些列表值时都会调用。我用来捕获调用参数的mock对象总是在列表中显示所有调用参数的最新值。下面的代码显示了该问题Python模拟方法调用参数显示列表的最后状态,python,unit-testing,mocking,Python,Unit Testing,Mocking,我有一个以列表为参数的函数。该函数被多次调用,并且每次更新某些列表值时都会调用。我用来捕获调用参数的mock对象总是在列表中显示所有调用参数的最新值。下面的代码显示了该问题 from mock import MagicMock def multiple_calls_test(): m = MagicMock() params = [0, 'some_fixed_value', 'some_fixed_value'] for i in xrange(1,10):
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()
这里是输出,注意所有调用的第一个列表元素都是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']
有没有办法强迫mock对象复制list参数,而不是保存对实际list的引用?或者用其他方法为每个方法执行断言正确的值?谢谢。不幸的是,这似乎是
mock
库的一个缺点,从代码来看,如果不修补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)
然后(为了说明明显的问题),只需将MagicMock
替换为CopyArgsMagicMock
,您就会看到所需的行为
请注意,这只针对提供的用例进行了测试,因此这可能不是解决问题的完整而健壮的解决方案,但希望它能被证明是有用的。尝试m.mock_调用。这将列出所有拨打的电话。我认为这应该奏效:
>>> from unittest.mock import MagicMock, call
>>> m = MagicMock()
>>> m('abc')
<MagicMock name='mock()' id='2634881401576'>
>>> m('def')
<MagicMock name='mock()' id='2634881401576'>
>>> call('abc') in m.mock_calls
True
>>> call('ghi') in m.mock_calls
False
>从unittest.mock导入MagicMock,调用
>>>m=MagicMock()
>>>m(‘abc’)
>>>m('def'))
>>>m.mock_调用中的调用('abc')
真的
>>>m.mock_调用中的调用('ghi')
假的
对于Python3.8,已接受的解决方案不再适用于我。但是,官方python文档中有一个解决方案:
您必须向下滚动一点才能找到以下内容: 另一种方法是创建Mock或MagicMock的子类来复制(使用copy.deepcopy())参数。下面是一个示例实现:
这对我的python 3.8很有用。谢谢。这确实有帮助。我只是想指出,调用方需要从Super()返回值才能从Mock获取返回值。@robjohncox,示例的最后一行应该使用
\u Mock\u self
作为Super
的第二个参数,而不是self
。谢谢。它确实有用!
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)