如何模拟文件IO,以便可以在单元测试中覆盖name属性?

时间:2019-04-15 23:31:36

标签: python-3.x mocking python-unittest

我正在尝试编写一个单元测试模拟程序,以打开一个文件并将其传递到使用它将JSON对象转储到的函数中。如何创建伪造的IO对象,该对象模仿打开文件句柄的行为,但使用类似的属性,特别是.name

在这里,我已经阅读了无数答案,并且所有答案都以各种方式解决了该问题。我已经尝试过模拟修补builtins.open,已经尝试过模拟修补open在模块内部被调用,但是我一直遇到的主要错误是,当我尝试访问伪造的IO对象的{ {1}}属性,我得到AttributeError:

.name

这是一个简单的函数,它以JSON格式将字典写入磁盘并采用打开的文件句柄:

AttributeError: 'CallbackStream' object has no attribute 'name'

这是我尝试进行单元测试的内容:

def generate(data, json_file):
  # data is a dict
  logging.info(f"Writing out spec file to {json_file.name}")
  json.dump(data, json_file)

但是,这会产生上面的AttributeError,在这里我不能使用 @patch("builtins.open", new_callable=mock_open()) def test_generate_json_returns_zero(self, mock_open): mocked_file = mock_open() mocked_file.name = "FakeFileName" data = {'stuff': 'stuff2'} generate(data, json_file=mocked_file) ,因为它不作为属性存在。我认为明确设置它会起作用,但是没有。

我可以通过`tempfile.TemporaryFile:使用临时文件来绕过此问题:

json_file.name

但这并不能解决 actual 问题,即我无法弄清楚如何模拟文件句柄,因此实际上不需要在磁盘上创建真实文件

我不能超越 def test_generate_json_returns_zero(self, mock_open): data = {'stuff': 'stuff2'} t = TemporaryFile("w") generate(data, json_file=t) 不是有效的属性。我该如何模拟文件对象,以便实际上可以使用IO对象的.name属性,并仍然对其伪造.name

2 个答案:

答案 0 :(得分:2)

new_callable参数是Mock的替代类,因此在您调用时:

@patch("builtins.open", new_callable=mock_open())

它通过将builtins.open返回而不是实际需要的mock_open()对象替换来修补MagicMock,因此将行更改为:

@patch("builtins.open")

它应该可以工作。

答案 1 :(得分:1)

您的测试从未真正调用过open,因此无需打补丁。只需使用您需要的属性创建一个Mock实例。

def test_generate_json_returns_zero(self):
    mocked_file = Mock()
    mocked_file.name = "FakeFileName"
    data = {'stuff': 'stuff2'}
    generate(data, json_file=mocked_file)