Создайте gzip-файл как объект для модульного тестирования - PullRequest
2 голосов
/ 27 февраля 2020

Я хочу протестировать функцию Python, которая читает файл gzip и извлекает что-то из файла (используя pytest).

import gzip

def my_function(file_path):
    output = []

    with gzip.open(file_path, 'rt') as f:
        for line in f:
            output.append('something from line')

    return output

Могу ли я создать файл gzip, подобный объекту, который я могу передать my_function? Объект должен иметь определенное содержимое и должен работать с gzip.open()

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

Ответы [ 2 ]

4 голосов
/ 29 февраля 2020

Вы можете использовать библиотеку io для создания файловых объектов в памяти. Пример:

def inmem():
    stream = io.BytesIO()
    with gzip.open(stream, 'wb') as f:
        f.write(b'spam\neggs\n')
    stream.seek(0)
    return stream
0 голосов
/ 27 февраля 2020

Это немного многословно, но я бы сделал что-то вроде этого (я предположил, что вы сохранили функцию my_function в файл с именем patch_one.py):

import patch_one  # this is the file with my_function in it
from unittest.mock import patch
from unittest import TestCase


class MyTestCase(TestCase):
    def test_my_function(self):
        # because you used "with open(...) as f", we need a mock context
        class MyContext:
            def __enter__(self, *args, **kwargs):
                return [1, 2]  # note the two items

            def __exit__(self, *args, **kwargs):
                return None

        # in case we want to know the arguments to open()
        open_args = None

        def f(*args, **kwargs):
            def my_open(*args, **kwargs):
                nonlocal open_args
                open_args = args
                return MyContext()

            return my_open

        # patch the gzip.open in our file under test
        with patch('patch_one.gzip.open', new_callable=f):  

            # finally, we can call the function we want to test
            ret_val = patch_one.my_function('not a real file path')

            # note the two items, corresponding to the list in __enter__()
            self.assertListEqual(['something from line', 'something from line'], ret_val)

            # check the arguments, just for fun
            self.assertEqual('rt', open_args[1])

Если вы хотите попробовать что-нибудь более сложное, Я бы порекомендовал прочитать макет юнит-тестовых документов, потому что то, как вы импортируете файл «patch_one», имеет значение, так же как и строка, которую вы передаете patch ().

Определенно найдется способ сделать это с помощью Mock или MagicMock, но я найти их немного сложными для отладки, поэтому я прошел долгий путь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...