如何模拟对__next__的调用

时间:2015-08-17 13:07:24

标签: python unit-testing python-3.x mocking

我正试图嘲笑一个协程。因此,这个模拟的__next__()close()被调用。在模仿close()时,我无法模仿__next__()

    mock_coroutine = mock.Mock()
    mock_coroutine.some_call(1, 2, 3)
    mock_coroutine.some_call.assert_called_with(1, 2, 3)
    mock_coroutine.close()
    mock_coroutine.close.assert_called_with()
    #this fails
    mock_coroutine.__next__()
    mock_coroutine.__next__.assert_called_with()

我错过了什么?如何确保我的模拟__next__()方法被调用?

目前,我正在使用以下内容:

class MockCoroutine:
    def __next__(self):
        self.called_next = True

    def close(self):
        self.called_exit = True

但是,我更倾向于使用标准模拟。

1 个答案:

答案 0 :(得分:4)

您需要使用MagicMock而不是Mock来默认使用__next__等魔术方法:

>>> from unittest import mock
>>> mock_coroutine = mock.MagicMock()
>>> mock_coroutine.__next__()
<MagicMock name='mock.__next__()' id='4464126552'>
>>> mock_coroutine.__next__.assert_called_with()

引自the documentation

  

Mock允许您将函数(或其他Mock实例)分配给魔术方法,并且它们将被适当调用。 MagicMock类只是一个Mock变体,它具有为您预先创建的所有魔法方法(好吧,所有有用的方法)。

所以,或者,您仍然可以使用常规Mock对象,但是您需要显式添加该属性:

>>> mock_coroutine = mock.Mock()
>>> mock_coroutine.__next__ = mock.Mock()
>>> mock_coroutine.__next__()
<Mock name='mock.__next__()' id='4464139232'>

这是因为尽管Mock在您访问它们时会动态创建属性,但任何具有前导和尾随下划线的属性都明确地免除了这些属性。见this footnote

  

唯一的例外是魔术方法和属性(具有前导和尾随双下划线的那些)。模拟不创建这些,而是​​提出AttributeError。这是因为解释器通常会隐式地请求这些方法,并且当它需要一个魔术方法时会得到一个新的Mock对象。如果您需要魔术方法支持,请参阅magic methods

但请注意,魔术方法通常是在类上查找,而不是实例,因此直接将__next__属性添加到Mock实例可以仍然失败; MagicMock课程会为您处理此特定问题。