我有以下代码。
import yaml
def load_yaml_file(filename):
with open(filename, 'rt') as f:
data = yaml.load(f)
return data
有没有一种方法可以模拟open
部分,使f变成'{"hello":"world"}'
,从而我可以断言数据被正确返回。
我试着用mock_open.return_value.__enter__.return_value = '{"hello":"world"}'
模拟打开,但无法使其正常工作。
我正在使用pytest和mocker。
免责声明
- 此解决方案不使用Mocker,但可以与pytest一起使用
- 此解决方案适用于Python>=3.6
正如你所说的你正在使用Mocker,我假设你正在使用一个非常旧的代码库(<=2.6(。我强烈建议你将代码移植到任何版本>=3.6
由于Python 3.3 mock已集成到unittest.mock中的标准lib中,并且是旧mock包的一个克隆
mock-lib有一个名为mock_open的功能,它完全可以满足您的需要,并有一个完全符合您需求的示例。
with patch('__main__.open', mock_open(read_data='bibble')) as m:
with open('foo') as h:
result = h.read()
m.assert_called_once_with('foo')
assert result == 'bibble'
根据您的需要调整解决方案,您可以使用此示例
import yaml
from unittest.mock import patch, mock_open
def load_yaml_file(filename):
with open(filename, 'rt') as f:
data = yaml.load(f)
return data
with patch('__main__.open', mock_open(read_data='{"hello":"world"}')) as m:
res = load_yaml_file('foo')
assert res == {"hello":"world"}
您根本不需要设置__enter__
。只需将要读取的数据作为read_data
参数传递给mock_open()
:
mocked_open = mock.mock_open(read_data='{"hello":"world"}')
with mock.patch("yourmodule.open", mocked_open):
result = load_yaml_file("foobar.yaml")
演示:
>>> import yaml
>>> def load_yaml_file(filename):
... with open(filename, 'rt') as f:
... data = yaml.load(f)
... return data
...
>>> from unittest import mock
>>> mocked_open = mock.mock_open(read_data='{"hello":"world"}')
>>> with mock.patch("__main__.open", mocked_open):
... result = load_yaml_file("foobar.yaml")
...
>>> print(result)
{'hello': 'world'}
>>> mocked_open.mock_calls
[call('foobar.yaml', 'rt'),
call().__enter__(),
call().read(4096),
call().read(4096),
call().__exit__(None, None, None)]