Как с помощью pytest протестировать запись в CSV на уровне формируемых им строк без записи в файл?

Прошу подсказать как мне протестировать функцию записи в csv-файл не записывая в файл, а поставив mock-объект в тот момент, когда очередная строчка уже сформирована?

from csv import DictWriter

def write_to_csv(filename, address, opcode) -> None:
    with open(filename, 'w', newline='') as csv_file:
        writer = DictWriter(csv_file, fieldnames=(
            'address', 'opcode'))
        writer.writeheader()
        writer.writerow({'address': address,
          'opcode': opcode})

Вот псевдокод того что хочу получить:

def test_write_to_csv():
    class CSVWriter:
        def write(row):
            self.row = row
    csv_writer = CSVWriter()
    with monkeypatch(DictWriter, csv_writer): 
        write_to_csv('opcodes.csv', 0xDA, 5)
        assert '0xDA,5' == csv_writer.row

В этом куске псевдокод я:

  • Создал патч-объект для накапливания сформированных строк для записи в CSV-файл
  • Я патчу стандартный объект DictWriter передав ему свой патч-объект, который накапливает строки
  • После вызываю тестируемую функцию write_to_csv
  • После выполнения тестируемой функции я проверяю результаты ее работы

Мой пример специально сужен до такого примитивного кода, чтоб проще было пояснить чего хочу добиться. Мне нужно в чужом проекте, править код которого у меня нет возможности протестировать запись CSV-файлы большого количества значений не ухудшив скорость работы автотестов. По этому мне очень хочется избежать фактических I/O операций и проверить итоговые csv-строки накопив их в памяти.

Мне непонятно как мне мой тест на псеводкоде превратить в работающий код. Как написать такой monkeypath-код, который патчит в тестовых целях стандартный модуль csv ?


Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Вот так можно мокнуть open и проверить результаты его работы:

from unittest import mock
import pytest

from csv import DictWriter


def write_to_csv(filename, address, opcode) -> None:
    with open(filename, 'w', newline='') as csv_file:
        writer = DictWriter(csv_file, fieldnames=(
            'address', 'opcode'))
        writer.writeheader()
        writer.writerow({'address': address,
          'opcode': opcode})


def test():
    with mock.patch('builtins.open', mock.mock_open()) as open_:
        write_to_csv('opcodes.csv', 0xDA, 5)
        open_.assert_called_once_with('opcodes.csv', 'w', newline='')
        assert open_().write.call_args_list == [
            mock.call('address,opcode\r\n'),
            mock.call('218,5\r\n')
        ]
→ Ссылка