Существуют ли фреймворки Fake File System для Java? [закрыто]


84

Я представляю тесты в проекте, который интенсивно использует операции ввода-вывода (в данном случае файловую систему). Система постоянно открывает / закрывает файлы, проверяет наличие файлов, удаляет их и так далее.

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

Кажется, ребята с рубином сделали это снова, и это именно то, что я прошу в рубине: http://ozmm.org/posts/fakefs.html .

Есть ли что-нибудь отдаленно похожее на Java?


1
Похоже, что на уровне приложения это легче сделать на языках без системы статических типов. В Java File / FileInputStream / FileOutputStream всегда будет ссылаться на файловую систему базовой системы - если вы не исправите виртуальную машину.
Паоло Эберманн 07

Существуют такие интерфейсы, как JavaFileManager или FileSystemView, которые вы могли бы реализовать, но большинство программ не будут их использовать.
Паоло Эберманн 07

@ 1-й комментарий: я это хорошо знаю. В настоящее время я заменил все варианты использования File на собственное имя файла, которое содержит только имя файла в виде строки. Вся логика ввода-вывода была сосредоточена на интерфейсе IFileSystem. Проблема, с которой я столкнулся, заключается в том, что для реализации поддельной файловой системы так, как мне было нужно, это был бы еще целый день (с поддержкой файлов + папок + скрытых файлов + переименований + получения только пути из имени файла + ...) и протестируем его, чтобы убедиться, что он действительно правильный.
пожрал элизиум 07

1
Поскольку вы упомянули Ruby в OP, я просто хотел бы добавить здесь, что есть эквивалент в C #, System.IO.Abstractions, который я начал использовать недавно, и он довольно хорош.
julealgon 06

Ответы:


53

У Google есть реализация в памяти Java 7 FileSystemProvider с открытым исходным кодом. Проект называется jimfs .


Если вы используете Java 6 или более раннюю версию, есть альтернатива: раньше я с большим успехом использовал Apache Commons VFS . Похоже, что это очень похоже на настраиваемый FileSystemProvider, упомянутый другим ответчиком в Java 7.

Он поставляется с предварительно загруженными реализациями нескольких файловых систем: File, RAM, S / FTP и Jar, чтобы назвать несколько. Еще видел плагин для S3 .


6
+1 к jimfs, что позволило мне протестировать мой код без единого изменения. (Я использовал Pathслучайно)
user1071136

36

В Java 6 и более ранних версиях это сложно, потому что классы любят Fileи не FileInputStreamпредоставляют возможности для отправки в разные «виртуальные файловые системы» в пространстве Java.

В Java 7 есть поддержка виртуальных файловых систем; см. « Разработка настраиваемого поставщика файловой системы» . Не знаю, позволит ли это вам делать то, что вы хотите, но это хорошее место для начала поиска.


Мех. Поскольку на самом деле, похоже, не существует какой-либо фальшивой файловой системы, я полагаю, что просто сам реализую минимальную реализацию. Я ничего не выигрываю, используя FileSystemProvider

На самом деле, вы ДЕЙСТВИТЕЛЬНО выигрываете, используя FileSystemProvider:

  • Вы реализуете что-то, что (если выпущено под лицензией с открытым исходным кодом) может быть очень полезно для других людей в вашем положении и для других целей.

  • Вы упростите себе задачу, если решите переключиться на FileSystemProvider, над которым прямо сейчас может работать кто-то другой.


Интересно, но, как кажется, мне все равно придется самому реализовать файловую систему, не так уж и полезно
;-(

7
По крайней мере, это позволяет вам это делать. И как вы сами сказали - «легко было бы настроить» .
Stephen C

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

@devoured elysium - смотрите мое обновление.
Stephen C

2
+1 за рекомендацию написания и открытого исходного кода решения
WickyNilliams

19

Вы можете использовать org.junit.rules.TemporaryFolderиз пакета JUnit :

Правило TemporaryFolder позволяет создавать файлы и папки, которые гарантированно будут удалены по завершении метода тестирования (независимо от того, пройден он или не прошел):

Пример:

final TemporaryFolder testFolder = new TemporaryFolder();
testFolder.create();
final Path filePath = testFolder.newFile("input.txt").toPath();
final Path dirPath = testFolder.newFolder("subfolder").toPath();

В качестве альтернативы выйти из .toPath()партии:

final File filePath = testFolder.newFile("input.txt");

TemporaryFolder не находится в памяти.
progonkpa

8

Вы можете абстрагироваться от использования File, используя намерение «где-то записывать данные», изменив свой API, чтобы использовать OutputStreamвместо a File, затем передать API a FileOutputStreamв производственном коде, но передать его ByteArrayOutputStreamиз ваших тестов. A ByteArrayOutputStream- это поток в памяти, поэтому он очень быстрый, и вы можете просто проверить его содержимое с помощью его методов - он идеально подходит для тестирования. Также есть соответствующий, ByteArrayInputStreamесли вы хотите читать данные.

Файловые системы, как правило, довольно быстрые - я бы не стал беспокоиться, если в ваших тестах не было много операций ввода-вывода файлов.

Обратите внимание, что создание Fileобъекта java не создает файл на диске, то есть следующий код не вызывает никаких изменений на диске:

File f = new File("somepath"); // doesn't create a file on disk

new File («что-то») не будет создавать файл на диске, но если вы попытаетесь запустить почти любой из его методов, он будет использовать файловую систему. Попробуйте новый файл ("xyz"). GetAbsolutePath (), чтобы понять, что я имею в виду ..
пожирал элизиум

1
Думаю, люди считают, что меня больше всего беспокоит скорость. Нет.
пожрал элизиум

1
Я считаю, что всегда полезно абстрагироваться от любых ресурсов, таких как файловые системы (так же, как вы пишете уровень доступа к данным в БД). обычно это достигается путем написания интерфейса и тонкой оболочки для класса самого низкого уровня. если вы используете внедрение зависимостей на самом высоком уровне своей программы, вы можете очень легко распространить фиктивную файловую систему (обратите внимание, что она не обязательно должна использовать фиктивную структуру, просто «фиктивную» реализацию интерфейса) через свое приложение.
WickyNilliams

@devouredelysium new File("xyz").getAbsolutePath()не делает абсолютно ничего бы то ни было , за исключением возвращает путь , что файл будет иметь , если он существовал. Это не меняет файловую систему; если файл не существует, он по-прежнему возвращает строку пути и не создает файл. Что вы имели в виду под «посмотрим, что произойдет»?
Bohemian

1
Fileне является окончательным в моем OpenJDK 7.
Дмитрий Лазерка

6

Jimfs от Google - это файловая система NIO в памяти, которая отлично подходит для тестов.


4

Простым способом было бы использовать способ предоставления вашей системы файловой системы, полностью основанной на ОЗУ - tempfs в Linux, RAM-диск в Windows.


Я не понимаю, что может быть лучше, чем использование настоящей файловой системы (кроме скорости).
пожрал элизиум

Да, основная причина - скорость (и износ диска). Извините, возможно, я неправильно понял вашу цель.
Паоло Эберманн,

1
Моя цель - облегчить себе тестирование. В настоящее время меня не волнует производительность.
пожрал элизиум

4

MockFTPServer, похоже, имеет несколько реализаций Fake Filesystem (Unix / Windows)

Похоже, вы можете использовать эти поддельные реализации файловой системы отдельно от любых концепций FTP. Я пробую это сейчас для тех же целей, что вы обрисовали.


Я использую UnixFakeFileSystem. Очень хорошо работает как поддельная реализация для моей абстракции FileSystem.
Deano

2

Я не уверен в конкретных фреймворках, но общий подход с точки зрения ООП заключался бы в написании некоторых абстрактных слоев поверх любого кода доступа к файлам (интерфейсов в изобилии!) и, возможно, фасада для облегчения использования общих операций. тогда вы просто имитируете один уровень ниже кода, который вы сейчас тестируете, и тогда это, по сути, поддельная файловая система (или, по крайней мере, код, который вы тестируете, иначе не узнает).

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

public interface IFileSystem {
   IFileHandle Load(string path);
   //etc
}

public class ClassBeingTested {
   public ClassBeingTested(IFileSystem fileSystem) {
      //assign to private field
   }

   public void DoSomethingWithFileSystem() {
       //utilise interface to file system here
       //which you could easily mock for testing purposes
       //by passing a fake implementation to the constructor
   }
}

Надеюсь, моя java верна, я давно не писал java, но, надеюсь, вы поймете дрейф. надеюсь, я не недооцениваю проблему и не слишком упрощаюсь!

конечно, все это предполагает, что вы имеете в виду истинное модульное тестирование, то есть тестирование минимально возможных единиц кода, а не всей системы. для интеграционного тестирования нужен другой подход.


1
Поддельная файловая система должна иметь собственную логику - это файловая система, как и любая другая, но существующая только в памяти. Я бы не хотел программировать себе такую ​​файловую систему.
пожрал элизиум 07

какой тип операций файловой системы вы хотите имитировать? блокировка файлов? чтение / письмо? или простые вещи, такие как открытие файлов, проверка наличия каталогов, создание файлов?
WickyNilliams

В основном это простые операции, связанные с проверкой того, являются ли файлы файлами или каталогами, если они существуют, для создания файлов, для удаления файлов. Это, конечно, при поддержке нескольких папок и операций, таких как «получить путь из этого файла», «получить относительный путь из абсолютного пути» и т. Д.
пожирал elysium

Я думаю, что, как я уже сказал, создаю отказ от физической файловой системы и всегда использую это (всегда кодируя интерфейс) во всем приложении. затем просто используйте инъекцию зависимостей, чтобы распространяться через вашего испытуемого. Я знаю, что это монотонная работа, но, как программисты, мы должны делать это, чтобы получить четкое разделение проблем и обеспечить простоту тестирования :)
WickyNilliams,

Вы действительно не понимаете, о чем здесь спрашивают. Если я ищу поддельную файловую систему, это должно быть потому, что я уже сделал абстракцию всей файловой системы в своем приложении (как указано в комментарии к OP). Мне просто нужна фальшивая реализация файловой системы для использования в моих тестах ..
пожирал элизиум

2

ShrinkWrap из проекта Arquillian, похоже, включает NIO-совместимую файловую систему памяти

Вы можете создать простую файловую систему в памяти, выполнив следующие действия:

FileSystem fs = ShrinkWrapFileSystems.newFileSystem(ShrinkWrap.create(GenericArchive.class))

Поддерживает ли он протокол file: //, не могу найти документацию ....
Марко Вазаполло,


0

Я искал "Поддельная файловая система Java" и нашел этот вопрос. К сожалению, это все, что я нашел. Я сам написал эту фальшивую файловую систему: https://github.com/dernasherbrezon/mockfs

Я использую его для имитации IOExceptions во время чтения / записи в файлы. IOException может произойти, например, из-за «отсутствия места на диске», что практически невозможно смоделировать другими способами.


-1

Это немного устарело, и это решение похоже только на Linux, но выглядит хорошо https://www.google.co.il/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=tmpfs%20on% 20ubuntu

tmpfs - это отображаемый каталог в памяти (данные исчезают при перезагрузке). После подключения данные могут быть скопированы в него и работать с ними из памяти.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.