模拟上下文管理器中使用的 Class

Mocking a Class used within a Context Manager

我有一个模块方法,它使用上下文管理器和 Class 提供迭代:

import module

def ReadLog(log_file):
  with module.LogReader(log_file) as reader:
    combined_list = []
    for record in reader:
      combined_list.append(record)
    return combined_list

在我的单元测试中,我试图模拟 module.LogReader 以便它生成我自己定义的记录。这是我目前所在的位置:

import mock
import my_mod

@mock.patch.object(my_mod.module, 'LogReader')
def testReadLog(self, mock_logreader):
  filename = '/fake/file/name.log'
  my_mod.ReadLog(filename)

  # Verify that module.LogReader was called
  mock_logreader.assert_called_once_with(filename)

但到目前为止我还无法使迭代产生记录。 LogReader class 有 __enter__, __exit__, __iter__, next 方法,我试过 mock_logreader.return_value = '123' 但这会导致错误消息 AttributeError: __exit__.

我在这里缺少什么调味料?

在调用要测试的函数之前,您需要对要模拟的函数设置 return_value。请注意,在您未设置此项的任何地方,它将 return 一个新的 MagicMock。您可以通过在这个新 MagicMock.

上设置 return_value 来拦截它

例如:

file = 'foo' 
mock = MagicMock()  # could be gotten through patch
mock(file).__enter__().__iter__.return_value = [1,2,3,4,5]

with mock(file) as reader:
    for x in reader:
        print(x)

请参阅 Python data model 了解魔术功能的工作原理。