我正在尝试编写一个单元测试模拟程序,以打开一个文件并将其传递到使用它将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
?
答案 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)