我正在使用 python 2.7.15rc1 。我正在尝试模拟一个迭代器,以便在对其进行迭代时会引发异常。 例如:
elements = [1,2,3,Exception('boom!')]
iterable = <create a mock iterable to iterate over "elements">
# this does not print anything.
for value in iterable:
...
我尝试在side_effect
实例的next()
方法上使用MagicMock
属性,如下所示:
from mock import MagicMock
mocked_next = MagicMock()
mocked_next.next.side_effect = [1,2,3,Exception('boom!')]
mocked_iterable = MagicMock()
mocked_iterable.__iter__.return_value = mocked_next
...
# This does not print anything and no exception is raised
for value in mocked_iterable:
print(value)
我假设for
循环最终会在__iter__
上调用mocked_iterable
,该循环返回另一个具有next
属性且具有side_effect
的模拟对象。我的期望是,循环最终将调用mocked_next.next()
,这将迭代我在side_effect
中为其提供的列表。
很显然,我的理解是不正确的。我在这里想念什么?可以仅使用模拟来实现这一点,还是必须创建一个自定义迭代器来实现此行为?
编辑:我正在尝试测试在可迭代对象上迭代的一段代码的异常处理部分,因此试图模拟引发异常的迭代器。
答案 0 :(得分:1)
您要查找的内容不适合MagicMock
,因为side_effect
可以是例外,也可以是可迭代的,但不能同时是两者。相反,您应该使用__iter__
方法创建一个类,该类产生给定序列中的项,然后引发给定异常:
class ExceptionRaisingIterable:
def __init__(self, seq, exception):
self.seq = seq
self.exception = exception
def __iter__(self):
for i in self.seq:
yield i
raise self.exception
for value in ExceptionRaisingIterable([1, 2, 3], Exception('boom!')):
print(value)
这将输出:
1
2
3
Traceback (most recent call last):
File "test.py", line 11, in <module>
for value in ExceptionRaisingIterable([1, 2, 3], Exception('boom!')):
File "test.py", line 9, in __iter__
raise self.exception
Exception: boom!