问题描述
我的一个类在一个列表中累积值,将该列表用作另一个对象的方法的参数,并删除该列表中的一些值.类似的东西
One of my classes accumulates values in a list, uses the list as an argument to a method on another object and deletes some of the values in this list. Something like
element = element_source.get() self.elements.append(element) element_destination.send(elements) self.remove_outdated_elements()
但是当我尝试测试这种行为时,我发现模拟不会复制他们的论点.
But when when i was trying to test this behavior, i've found that mocks don't copy their arguments.
>>> from unittest.mock import Mock >>> m = Mock() >>> a = [1] >>> m(a) <Mock name='mock()' id='139717658759824'> >>> m.call_args call([1]) >>> a.pop() 1 >>> m.assert_called_once_with([1]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python3.3/unittest/mock.py", line 737, in assert_called_once_with return self.assert_called_with(*args, **kwargs) File "/usr/lib/python3.3/unittest/mock.py", line 726, in assert_called_with raise AssertionError(msg) AssertionError: Expected call: mock([1]) Actual call: mock([])
有没有办法让 Mock 复制它的调用参数?如果不是,那么测试这种行为的最佳方法是什么?
Is there a way to make Mock copy it's call arguments? If not, what is the best way to test this kind of behavior?
推荐答案
有个章节Coping with mutable arguments" 在文档中,它为您的问题提出了几种解决方案.
There is a chapter "Coping with mutable arguments" in the documentation, which suggests several solutions to your problem.
我会选择这个:
>>> 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) ... >>> c = CopyingMock(return_value=None) >>> arg = set() >>> c(arg) >>> arg.add(1) >>> c.assert_called_with(set()) >>> c.assert_called_with(arg) Traceback (most recent call last): ... AssertionError: Expected call: mock(set([1])) Actual call: mock(set([])) >>> c.foo <CopyingMock name='mock.foo' id='...'>