Как реализовать unit test для функции записи данных в файл
Что проверяют
Понимаете ли вы, как тестировать код с побочным эффектом на диске и не зависеть при этом от окружения. Следом обычно просят показать, как проверить ветку с ошибкой записи, которую на реальной файловой системе трудно воспроизвести.
Как отвечать
Есть два рабочих подхода, и сильный ответ называет оба.
Первый: писать по-настоящему, но в изолированный каталог. В setUp создаётся уникальная папка FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString), в tearDown она удаляется. Пути собирайте через URL, а не склейкой строк. Тест быстрый, проверяет реальную запись и не мешает соседям при параллельном прогоне.
Второй: вынести файловые операции за протокол, например FileWriting с методом write(_ data: Data, to url: URL) throws, и передавать его в тестируемый класс. В тесте подставляется фейк, который запоминает вызовы или бросает заданную ошибку. Так проверяются ветки «диск заполнен» и «нет прав», не трогая диск.
Что проверять:
- содержимое: прочитали файл через
Data(contentsOf:)и сравнили с записанным; - перезапись: второй вызов заменяет файл, а не дописывает;
- атомарность: запись идёт с опцией
.atomic, чтобы при сбое не остался обрезанный файл; - ошибки: функция пробрасывает ошибку наружу, тест ловит её через
XCTAssertThrowsErrorили#expect(throws:)в Swift Testing.
Если функция возвращает Bool и глотает ошибку, скажите об этом: сигнатура с throws и тестируется, и отлаживается лучше.
Где спотыкаются
Пишут в Documents или в общий временный каталог под фиксированным именем и не убирают за собой. Результат теста начинает зависеть от прошлого прогона и от порядка запуска.
Мокают весь FileManager наследованием. Получается тест заглушки, а не кода, и он ломается при любом изменении реализации.
Проверяют ошибку записи через «заведомо неправильный путь». Такой тест проверяет поведение файловой системы конкретной среды, а в симуляторе и на устройстве оно может отличаться. С фейком ошибка задаётся явно.