Модульный тестовый модуль Python 3 Context Manager - PullRequest
0 голосов
/ 13 ноября 2018

У меня есть следующий бит кода.

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.

Ответы [ 2 ]

0 голосов
/ 25 ноября 2018

Вам вообще не нужно устанавливать __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)]
0 голосов
/ 24 ноября 2018

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ

  • Это решение не использует Mocker, но может использоваться с pytest.
  • Это решение работает для Python> = 3.6

Поскольку вы сказали, что используете Mocker, я предполагаю, что вы работаете над очень старой базой кода (<= 2.6). Я настоятельно рекомендую вам перенести код на любую версию> = 3.6

Поскольку Python 3.3 mock интегрирован в стандартную библиотеку lib в unittest.mock и является в значительной степени клоном из старого пакета 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"}
...