4
from mock import MagicMock, call
m = MagicMock()
m.foo()
for i in m:
    print m
m.bar()
print m.mock_calls
[call.foo(), call.__iter__(), call.bar()]

[call.foo(), call.__iter__(), call.bar()] == m.mock_calls
False

如何断言模拟对象在一系列调用中被迭代?如果我设置其他内容,也会发生同样的事情__iter__.return_value

4

4 回答 4

4

一个有效但丑陋的解决方案是[call.foo(), ('__iter__', (), {}), call.bar()] == m.mock_calls.

于 2013-04-19T15:13:18.227 回答
2

根本问题是mock.call返回 的实例mock._Call,它本身就是 的子类tuple。作为一个元组,它继承了元组的__iter__方法,并且您将获得该实际方法,而不是像往常一样动态捕获属性访问以产生链式调用。

('__iter__', (), {})一种可能比在呼叫列表中硬编码更好的解决方法是这样做call.__getattr__('__iter__')(),其效果大致相同:

>>> mock.call.__getattr__('__iter__')() == ('__iter__', (), {})
True

(请注意,您不能这样做getattr(mock.call, '__iter__'),因为那只会tuple.__iter__再次为您提供实际方法)

或者,您可以子类mock._Call化并构建自己的行为更好(至少相对于__iter__)版本call

class _IterCall(mock._Call):

    def __getattr__(self, attr):
        if self._mock_name is None:
            return type(self)(name=attr, from_kall=False)
        name = '%s.%s' % (self._mock_name, attr)
        return type(self)(name=name, parent=self, from_kall=False)

    def __iter__(self):
        return self.__getattr__('__iter__')()


iter_call = _IterCall(from_kall=True)

(它也必须重写__getattr__,因为 的实现mock._Call.__getattr__将显式返回原始mock._Call类的实例而不是type(self)

>>> iter_call.__iter__() == ('__iter__', (), {})
True

这两种方法都有其缺点。

于 2019-12-18T12:44:46.600 回答
0

如果调用了模拟对象,则其called属性为True

>>> m = MagicMock()
>>> assert m.__iter__.called, "The object was not iterated over"
Traceback (most recent call last):
  File "<string>", line 1, in <fragment>
builtins.AssertionError: The object was not iterated over
>>> for i in m:
...     print(m)
... 
>>> assert m.__iter__.called, "The object was not iterated over"
>>> m.__iter__.called
True

在这种情况下m.__iter__也是一个模拟,它是“按需”创建的(作为访问__iter__方法的结果)。

于 2013-04-19T14:11:49.683 回答
0

我尽量避免猜测正确的语法,所以我编写了一个帮助库来根据实际调用为我生成断言。

如果您将以下行添加到代码的末尾:

import mock_autogen.generator
print(mock_autogen.generator.generate_asserts(m))

你会得到:

m.foo.assert_called_once_with()
m.__iter__.assert_called_once_with()
m.bar.assert_called_once_with()

所以不再需要自己弄清楚确切的语法,只需应用该工具 :)

于 2019-10-02T14:02:37.283 回答