模拟迭代器引发异常

时间:2019-04-03 18:26:36

标签: python python-2.7 unit-testing iterator mocking

我正在使用 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中为其提供的列表。

很显然,我的理解是不正确的。我在这里想念什么?可以仅使用模拟来实现这一点,还是必须创建一个自定义迭代器来实现此行为?

编辑:我正在尝试测试在可迭代对象上迭代的一段代码的异常处理部分,因此试图模拟引发异常的迭代器。

1 个答案:

答案 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!