Как протестировать следующий код с помощью mock (используя mocks, декоратор патчей и часовые, предоставляемые фреймворком Michael Foord ):
def testme(filepath):
with open(filepath, 'r') as f:
return f.read()
python
mocking
with-statement
Дэрил Спитцер
источник
источник
Ответы:
Способ сделать это изменился в mock 0.7.0, который, наконец, поддерживает насмешку над методами протокола python (магические методы), особенно с использованием MagicMock:
http://www.voidspace.org.uk/python/mock/magicmock.html
Пример макета, открытого как менеджер контекста (со страницы примеров в документации макета):
источник
__enter__
и имитирует__exit__
объекты - является ли последний подход устаревшим или все еще полезным?file
исчезла!mock_open
является частьюmock
фреймворка и очень прост в использовании.patch
используется в качестве контекста и возвращает объект, используемый для замены исправленного: вы можете использовать его для упрощения теста.Python 3.x
Используйте
builtins
вместо__builtin__
.Python 2.7
mock
не является частью,unittest
и вы должны исправить__builtin__
Чехол для декоратора
Если вы будете использовать в
patch
качестве декоратора, используяmock_open()
результат в качествеnew
patch
аргумента, это может быть немного странно.В этом случае лучше использовать
new_callable
patch
аргумент 's' и помнить, что все лишние аргументы, которыеpatch
не используются, будут переданы вnew_callable
функцию, как описано вpatch
документации .Например, оформленная версия для Python 3.x :
Помните, что в этом случае
patch
вы добавите фиктивный объект в качестве аргумента вашей тестовой функции.источник
with patch("builtins.open", mock_open(read_data="data")) as mock_file:
ли преобразовать в синтаксис декоратора? Я пытался, но я не уверен, что мне нужно передать в@patch("builtins.open", ...)
качестве второго аргумента.return_value
наmock_open
в другой фиктивный объект и утверждающие второй фиктивной - хreturn_value
), но он работал, добавляя вmock_open
качествеnew_callable
.six
модуль, чтобы иметь согласованныйmock
модуль. Но я не знаю, отображается ли он такжеbuiltins
в общем модуле.В последних версиях mock вы можете использовать действительно полезный помощник mock_open :
источник
.write
звонков?handle.write.assert_any_call()
. Вы также можете использоватьhandle.write.call_args_list
для получения каждого звонка, если порядок важен.m.return_value.write.assert_called_once_with('some stuff')
лучше имо. Избегает регистрации звонка.Mock.call_args_list
безопаснее, чем вызывать любой изMock.assert_xxx
методов. Если вы неправильно произнесете заклинание, будучи атрибутом Mock, они всегда будут молчаливо проходить.Чтобы использовать mock_open для простого файла
read()
(исходный фрагмент mock_open, уже приведенный на этой странице , предназначен для записи):Обратите внимание, что в соответствии с документами для mock_open, это специально для
read()
, поэтому не будет работать с общими шаблонами, такими какfor line in f
, например.Использует python 2.6.6 / mock 1.0.1
источник
for line in opened_file:
типом кода. Я попытался поэкспериментировать с итеративным StringIO, который реализует__iter__
и использует его вместоmy_text
, но не повезло.read()
так что не будет работать в вашемfor line in opened_file
случае; Я отредактировал пост, чтобы уточнитьfor line in f:
поддержка может быть достигнута путем насмешливого возвращаемое значение ,open()
как объект а вместо StringIO .with open("any_string") as f: print f.read()
Верхний ответ полезен, но я немного расширил его.
Если вы хотите установить значение вашего файлового объекта (
f
inas f
) на основе аргументов, переданныхopen()
вот один из способов сделать это:По сути,
open()
вернет объект иwith
вызовет__enter__()
этот объект.Чтобы правильно издеваться, мы должны
open()
возвращать ложный объект. Этот фиктивный объект должен затем имитировать__enter__()
вызов (MagicMock
будет делать это для нас), чтобы вернуть фиктивный объект данных / файлов, который мы хотим (следовательноmm.__enter__.return_value
). Выполнение этого с помощью 2 mocks описанным выше способом позволяет нам захватывать передаваемые аргументыopen()
и передавать их нашемуdo_something_with_data
методу.Я передал весь макет файла в виде строки,
open()
и мойdo_something_with_data
был похож на это:Это преобразует строку в список, поэтому вы можете сделать следующее, как если бы вы работали с обычным файлом:
источник
__enter__
? Это определенно больше похоже на взлом, чем рекомендуемый способ.Возможно, я немного опоздал к игре, но это сработало для меня при вызове
open
другого модуля без необходимости создания нового файла.test.py
MyObj.py
Прикрепив
open
функцию внутри__builtin__
модуля к моейmock_open()
, я могу издеваться над записью в файл, не создавая его.Примечание. Если вы используете модуль, который использует Cython, или ваша программа каким-либо образом зависит от Cython, вам нужно будет импортировать модуль Cython,
__builtin__
включив егоimport __builtin__
в начало вашего файла. Вы не сможете издеваться над универсальным,__builtin__
если вы используете Cython.источник
import __builtin__
в мой тестовый модуль. Эта статья помогла выяснить, почему эта техника работает так же хорошо, как и она: ichimonji10.name/blog/6Чтобы исправить встроенную функцию open () с помощью unittest:
Это сработало для патча для чтения конфига json.
Перемещаемый объект - это объект io.TextIOWrapper, возвращаемый функцией open ().
источник
Если вам больше не нужен файл, вы можете украсить тестовый метод:
источник