Найти - Пользователи
Полная версия: Python 2.7, mock file open, for line in file
Начало » Python для экспертов » Python 2.7, mock file open, for line in file
1
Master_Sergius
Здравствуйте. 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

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

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

 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
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB