我正试图嘲笑一个协程。因此,这个模拟的__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
但是,我更倾向于使用标准模拟。
答案 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()
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
课程会为您处理此特定问题。