Лучшие практики для зависимостей файловой системы в модульных / интеграционных тестах
Я только начал писать тесты для большого количества кода. Есть куча классов с зависимостями от файловой системы, то есть они читают файлы CSV, читают / пишут файлы конфигурации и так далее.
В настоящее время тестовые файлы хранятся в тестовой директории проекта (это проект Maven2), но по нескольким причинам этот каталог не всегда существует, поэтому тесты не пройдены.
Знаете ли вы лучшие методы для работы с зависимостями файловой системы в модульных / интеграционных тестах?
Изменить: я не ищу ответ для этой конкретной проблемы, которую я описал выше. Это был просто пример. Я бы предпочел общие рекомендации, как обрабатывать зависимости от файловой системы / баз данных и т. Д.
5 ответов
Во-первых, следует попытаться держать модульные тесты подальше от файловой системы - см. Этот Набор правил модульного тестирования. Если возможно, ваш код должен работать с потоками, которые будут буферами (т.е. в памяти) для модульных тестов, и FileStream в рабочем коде.
Если это невозможно, вы можете сделать так, чтобы ваши юнит-тесты генерировали нужные им файлы. Это облегчает чтение теста, так как все в одном файле. Это также может предотвратить проблему с разрешениями.
Вы можете смоделировать файловую систему / базу данных / доступ к сети в ваших модульных тестах.
Вы можете рассматривать модульные тесты, которые используют БД или файловые системы, как интеграционные тесты.
Зависимости от файловой системы здесь бывают двух видов:
- файлы, от которых зависят ваши тесты; если вам нужны файлы для запуска теста, вы можете сгенерировать их в своих тестах и поместить в
/tmp
каталог. - файлы, от которых зависит ваш код: файлы конфигурации или входные файлы.
Во втором случае часто можно реструктурировать код, чтобы удалить зависимость от файла (например, java.io.File можно заменить на java.io.InputStream
а также java.io.OutputStream
и т. д.) Это может быть невозможно, конечно.
Вам также может понадобиться обработать "недетерминированность" в файловой системе (однажды я выполнял отладку чего-то в NFS). В этом случае вам, вероятно, следует обернуть файловую систему в тонкий интерфейс.
В простейшем случае это просто вспомогательные методы, которые принимают файл и пересылают вызов в этот файл:
InputStream getInputStream(File file) throws IOException {
return new FileInputStream(file);
}
Затем вы можете заменить его на макет, который вы можете указать, чтобы бросить исключение, или вернуть ByteArrayInputStream
или что угодно.
То же самое можно сказать о URL и URI.
Есть два варианта тестирования кода, который нужно читать из файлов:
Храните файлы, связанные с модульными тестами, в системе контроля версий (например, в папке с тестовыми данными), чтобы у каждого, кто получит последнюю версию и запустит тесты, всегда были соответствующие файлы в известной папке относительно тестовых двоичных файлов. Это, наверное, "лучшая практика".
Если рассматриваемые файлы огромны, вы можете не захотеть держать их под контролем исходного кода. В этом случае сетевой ресурс, доступный всем разработчикам и сборщикам, вероятно, является разумным компромиссом.
Очевидно, что большинство хорошо написанных классов не будут иметь жестких зависимостей от файловой системы.
Дайте файлам теста, как входящим, так и выходным, имена, которые структурно похожи на имя модульного теста.
Например, в JUnit я бы использовал:
File reportFile = new File("tests/output/" + getClass().getSimpleName() + "/" + getName() + ".report.html");
Обычно тесты файловой системы не очень важны: файловая система хорошо понятна, проста в настройке и поддерживает стабильность. Кроме того, доступы, как правило, довольно быстрые, так что нет никаких оснований избегать их или издеваться над тестами.
Я предлагаю вам выяснить, почему этот каталог не существует, и убедиться, что он существует. Например, проверьте наличие файла или каталога в setUp() и скопируйте файлы, если проверка не удалась. Это происходит только один раз, поэтому влияние на производительность минимально.