Уведомления

Группа в Telegram: @pythonsu

#1 Авг. 13, 2017 13:12:19

Master_Sergius
Зарегистрирован: 2013-09-12
Сообщения: 271
Репутация: +  7  -
Профиль   Отправить e-mail  

Python 2.7, mock file open, for line in file

Здравствуйте. 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'

Но, что если файл считывается строка за строкой, циклом for? Не помогает ни StringIO, ни даже если параметром read_data передать тупо список строк.

 from mock import patch, mock_open
from StringIO import StringIO
 
filedata = """This is line1
and this is line2
and here is line3
"""
filedata_for_line = StringIO(filedata)
 
with patch('__main__.open', mock_open(read_data=filedata_for_line)) as m:
    with open('foo') as f:
        for line in f:
            print line
with patch('__main__.open', mock_open(read_data=filedata.split('\n'))) as m:
    with open('foo') as f:
        for line in f:
            print line

То есть, ни один из примеров выше не работает. Просто ничего не выводит. Что делать, как быть, кто виноват?



———————————————————————————
Мой блог о семействе *nix: http://nixtravelling.blogspot.com/

Отредактировано Master_Sergius (Авг. 13, 2017 14:45:45)

Офлайн

#2 Авг. 13, 2017 17:19:51

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Python 2.7, mock file open, for line in file

Не работает конструкция

 for line in f
для данного мока. Замени на
 for line in f.readlines()
или построчно считывай, и убери StringIO на обычную строку



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#3 Авг. 13, 2017 18:28:38

Master_Sergius
Зарегистрирован: 2013-09-12
Сообщения: 271
Репутация: +  7  -
Профиль   Отправить e-mail  

Python 2.7, mock file open, for line in file

JOHN_16
Не работает конструкция
for line in f
для данного мока. Замени на
for line in f.readlines()
или построчно считывай, и убери StringIO на обычную строку

Ну, хорошо. Но, что делать, если у меня функция такого плана (for line in f), и надо написать юниттесты?



———————————————————————————
Мой блог о семействе *nix: http://nixtravelling.blogspot.com/

Офлайн

#4 Авг. 13, 2017 23:02:42

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Python 2.7, mock file open, for line in file

точного ответа я не знаю. Могу предположить что выкинуть mock_open и написать свою мокирующую функцию: которая бы это умела



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#5 Авг. 14, 2017 12:12:57

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9716
Репутация: +  842  -
Профиль   Отправить e-mail  

Python 2.7, mock file open, for line in file

Master_Sergius
То есть, ни один из примеров выше не работает. Просто ничего не выводит. Что делать, как быть, кто виноват?
Наверное, mock_open() лезет в __enter__(), __exit__() и в read(). А цикл for вызывает __iter__(), который возвращает итератор строк и вот по нему оно уже гуляет. Так что можешь сделать обычный мок (без mock_open()) для функции open() и там должен возвращаться мок-объект из её return'а, у которого нужно у метода __iter__() подменить return, в который и ставятся строки. Я такое делал где-то давно; помню, что нормально работало.



Отредактировано py.user.next (Авг. 14, 2017 12:14:09)

Офлайн

#6 Авг. 14, 2017 13:07:38

Master_Sergius
Зарегистрирован: 2013-09-12
Сообщения: 271
Репутация: +  7  -
Профиль   Отправить e-mail  

Python 2.7, mock file open, for line in file

Да, товарищи (или приятней - добрые человеки), вы оба правы. Вот решение:

 def create_file_mock(data):                                                     
     mock_obj = mock.mock_open(read_data=data)                                   
     mock_obj.return_value.__iter__.return_value = data.splitlines()             
     return mock_obj
 
with mock.patch('__builtin__.open', create_file_mock(filedata)) as m:
     with open('foo') as f:                                              
           for line in f:                                                  
                 print line



———————————————————————————
Мой блог о семействе *nix: http://nixtravelling.blogspot.com/

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version