Python 3 Context Manager模拟单元测试

时间:2018-11-13 14:06:04

标签: python-3.x unit-testing mocking pytest

我有以下代码。

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和嘲笑者。

2 个答案:

答案 0 :(得分:1)

免责声明

  • 此解决方案不使用Mocker,但可以与pytest一起使用。
  • 此解决方案适用于Python> = 3.6

正如您所说的,您正在使用Mocker,我将假设您正在使用非常旧的代码库(<= 2.6)。我强烈建议您将代码移植到任何版本=> 3.6

由于Python 3.3模拟已集成到unittest.mock中的标准库中,并且是old mock package的相当多的克隆

模拟库具有一个名为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"}

答案 1 :(得分:1)

您根本不需要设置__enter__。只需将要读取的数据作为read_data的{​​{1}}参数传递:

mock_open()

演示:

mocked_open = mock.mock_open(read_data='{"hello":"world"}')
with mock.patch("yourmodule.open", mocked_open):
    result = load_yaml_file("foobar.yaml")