Издевательство "с открытым ()" - PullRequest
0 голосов
/ 31 октября 2018

Я пытаюсь выполнить модульное тестирование метода, который читает строки из файла и обрабатывает его.

with open([file_name], 'r') as file_list:
    for line in file_list:
        # Do stuff

Я попробовал несколько способов, описанных в других вопросах, но ни один из них, похоже, не подходит для этого случая. Я не совсем понимаю, как python использует объект файла как итеративный в строках, он внутренне использует file_list.readlines ()?

Этот способ не сработал:

    with mock.patch('[module_name].open') as mocked_open: # also tried with __builtin__ instead of module_name
        mocked_open.return_value = 'line1\nline2'

Я получил

AttributeError: __exit__

Может быть, потому что оператор with имеет этот специальный атрибут для закрытия файла?

Этот код делает file_list MagicMock. Как мне хранить данные на этом MagicMock, чтобы перебирать его?

with mock.patch("__builtin__.open", mock.mock_open(read_data="data")) as mock_file:

С наилучшими пожеланиями

1 Ответ

0 голосов
/ 31 октября 2018

Возвращаемое значение mock_open (до Python 3.7.1) не предоставляет работающий метод __iter__, что может сделать его непригодным для тестирования кода, который повторяется в открытом объекте файла.

Вместо этого я рекомендую рефакторинг вашего кода, чтобы получить уже открытый файлоподобный объект. То есть вместо

def some_method(file_name):
    with open([file_name], 'r') as file_list:
        for line in file_list:
            # Do stuff

...

 some_method(file_name)

напишите как

def some_method(file_obj):
    for line in file_obj:
        # Do stuff

...

with open(file_name, 'r') as file_obj:
    some_method(file_obj)

Это превращает функцию, которая должна выполнять IO, в чисто (r) функцию, которая просто перебирает любой файлоподобный объект. Чтобы проверить это, вам не нужно издеваться над open или ударять по файловой системе; просто создайте StringIO объект для использования в качестве аргумента:

def test_it(self):
    f = StringIO.StringIO("line1\nline2\n")
    some_method(f)

(Если вы все еще чувствуете необходимость написать и протестировать оболочку, например

def some_wrapper(file_name):
    with open(file_name, 'r') as file_obj:
        some_method(file_obj)

обратите внимание, что вам не нужно проверенное открытое, чтобы делать что-то конкретное. Вы проверяете some_method отдельно, поэтому единственное, что вам нужно сделать для проверки some_wrapper, это убедиться, что возвращаемое значение open передано some_method. open, в этом случае, может быть простым старым издевательством без особого поведения.)

...