Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a mock side_effect iterator be reset after it has been exhausted?

mock.reset_mock() will not reset a side effect iterator. Is there a way to do this without creating the mock again?

>>> 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)
>>> 

The intent is to re-use the mock in subsequent tests but I suspect that, like a generator, it cannot be restarted.

So (better late than never) after being pointed in the right direction I looked in mock.py and found that side_effect is an iterator object (which cannot be reset once exhausted):

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

and def reset_mock() does not address the side efect.

like image 562
wwii Avatar asked Sep 13 '14 18:09

wwii


2 Answers

Note that since Python 3.6, you can reset the mock side_effect and return_value with:

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

From the docs:

In case you want to reset return_value or side_effect, then pass the corresponding parameter as True. Child mocks and the return value mock (if any) are reset as well.

like image 134
Antoni Szych Avatar answered Nov 03 '22 11:11

Antoni Szych


As user2357112 commented, reassigning side_effect will solve you problem.

>>> from mock import MagicMock
>>>
>>> lst = [1, 2]
>>> mock = MagicMock(side_effect=lst)
>>> mock(), mock()
(1, 2)
>>> mock.side_effect = lst  # <-------
>>> mock(), mock()
(1, 2)
like image 9
falsetru Avatar answered Nov 03 '22 09:11

falsetru