Why does Mock side_effect stop with StopIteration?
Why does Mock side_effect stop with StopIteration?
A Mock with list-backed side_effect stops with StopIteration because each call consumes one item from the configured iterable. Once the fixture makes a third call after two scripted responses, there is no next item to provide.
The first mock has exactly two values: first and second. The assertions establish that those are returned in order. The third invocation raises StopIteration; it does not prove that a real dependency failed, timed out, or returned an invalid response. It proves only that this test double's response script was exhausted. Checking call_count == 3 also shows that the failed invocation still counts as an attempted call.
If the behavior should continue after a finite sequence, encode that rule instead of relying on an oversized list. The second mock uses a callable fallback that returns a deterministic value for every call. Its two calls yield separate values and record their arguments. A callable can also raise domain-specific exceptions or return DEFAULT when a configured return_value should apply.
unittest.mock has been available in the standard library since Python 3.3. The official side_effect documentation specifies that iterables provide one value per call.
AI assistance disclosure: this article and executable synthetic fixture were drafted with AI assistance.
from unittest.mock import Mock
scripted = Mock(side_effect=["first", "second"])
assert scripted() == "first"
assert scripted() == "second"
try:
scripted()
except StopIteration:
exhausted = True
else:
exhausted = False
assert exhausted
assert scripted.call_count == 3
def fallback(index):
return f"fallback-{index}"
continuous = Mock(side_effect=fallback)
assert continuous(3) == "fallback-3"
assert continuous(4) == "fallback-4"
continuous.assert_any_call(3)
continuous.assert_any_call(4)
print("scripted responses: first, second")
print("third scripted call: StopIteration")
print("callable fallback: fallback-3, fallback-4")
scripted responses: first, second
third scripted call: StopIteration
callable fallback: fallback-3, fallback-4