在所有迭代器都已耗尽后,是否可以重置模拟的`side_effect`迭代器?

15

mock.reset_mock() 不会重置副作用迭代器。 有没有一种方法可以在不再创建模拟的情况下完成这个操作?

mock.reset_mock() 不会重置副作用迭代器。请问是否有其他方法可以在不需要重新创建模拟对象的情况下实现此功能?

>>> from mock import MagicMock
>>> mock = MagicMock(side_effect = [1,2])
>>> mock(), mock()
(1, 2)
>>> mock()

Traceback (most recent call last):
  File "<pyshell#114>", line 1, in <module>
    mock()
  File "C:\Python27\Lib\site-packages\mock.py", line 955, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "C:\Python27\Lib\site-packages\mock.py", line 1013, in _mock_call
    result = next(effect)
StopIteration
>>> mock.reset_mock()
>>> mock()

Traceback (most recent call last):
  ...
StopIteration
>>> mock = MagicMock(side_effect = [1,2])
>>> mock(), mock()
(1, 2)
>>> 

目的是在后续测试中重复使用模拟,但我怀疑它像生成器一样不能被重新启动。

因此(迟到总比不到好),在被指向正确方向后,我查看了mock.py并发现side_effect是一个迭代器对象(一旦用尽就无法重置):

def __set_side_effect(self, value):
    value = _try_iter(value)
    ...

def _try_iter(obj):
    ...
    try:
        return iter(obj)
    except TypeError:
        # XXXX backwards compatibility
        # but this will blow up on first call - so maybe we should fail early?
        return obj

def reset_mock()并未解决副作用问题。


2
如何传递无限迭代器?mock = MagicMock(side_effect=itertools.cycle([1,2]));您不需要调用reset_mock - falsetru
1
@falsetru:但是如果模拟被错误地使用,下一次调用模拟将会给出错误的值。 - Martijn Pieters
3
你尝试重新分配 side_effect 了吗? - user2357112
重新分配迭代器正是我所需要的,但使用itertools.xyz作为side_effect将会非常方便,谢谢。 - wwii
2个回答

12

如用户2357112所评论的那样,重新赋值side_effect将解决您的问题。

>>> from mock import MagicMock
>>>
>>> lst = [1, 2]
>>> mock = MagicMock(side_effect=lst)
>>> mock(), mock()
(1, 2)
>>> mock.side_effect = lst  # <-------
>>> mock(), mock()
(1, 2)

谢谢,我甚至没有想过尝试那个。你比@user2357112更快。 - wwii

4

自Python 3.6以来,可以使用以下方式重置模拟的side_effectreturn_value

mock.reset_mock(return_value=True, side_effect=True)

这将会:

  • return_value 恢复为模拟的默认值
  • side_effect 恢复为模拟的默认值 None。它不会将 side_effect 迭代器重置回其开头

来自文档

如果您想要重置 return_valueside_effect,则将相应参数传递为 True。子模拟和返回值模拟(如果有)也将被重置。


2
对于我在问题中的简单示例,这并不会重置side_effect,以便可以再次使用它。它完全删除了副作用。让我的例子;打印mock.side_effect;重置它;然后再次打印mock.side_effect-你会发现它已经消失了。 - wwii
1
刚刚遇到了@wwii指出的问题。这里的文档需要一些澄清。 - robo
1
诚然,这并没有回答确切的问题,但提到重置模拟的side_effect=True选项仍然非常有帮助。在我的情况下,这个答案解除了我被卡住数小时无法通过测试用例的困境。 - raner
即使根据文档您的回答是正确的,在我的情况下它会引发错误,因为它不接受 return_value 作为参数。 - Seb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接