Gibt es Fake File System Frameworks für Java? [geschlossen]

82

Ich führe Tests in einem Projekt ein, das E / A-Operationen (in diesem Fall das Dateisystem) stark nutzt. Das System öffnet / schließt ständig Dateien, prüft, ob Dateien vorhanden sind, löscht sie usw.

Es wurde schnell klar, dass regelmäßiges Verspotten nicht viel nützen würde, da dies meine Tests schwer einzurichten und zu begründen machen würde. Auf der anderen Seite wäre es fantastisch, ein gefälschtes Dateisystem zu haben, und ich denke, es ist ziemlich einfach einzurichten.

Es scheint, dass die Ruby-Jungs es wieder getan haben, und es gibt genau das, wonach ich in Ruby frage : http://ozmm.org/posts/fakefs.html .

Gibt es etwas Ähnliches für Java?

verschlungenes Elysium
quelle
1
Es sieht so aus, als ob dies auf Anwendungsebene in Sprachen ohne statisches Typsystem einfacher ist. In Java verweist ein File / FileInputStream / FileOutputStream immer auf das Dateisystem des zugrunde liegenden Systems - wenn Sie die VM nicht patchen.
Paŭlo Ebermann
Es gibt Schnittstellen wie JavaFileManager oder FileSystemView, die Sie implementieren könnten, aber die meisten Programme verwenden sie nicht.
Paŭlo Ebermann
@ 1. Kommentar: Das weiß ich genau. Ich habe derzeit alle Verwendungen von Datei durch einen eigenen Dateinamen ersetzt, der nur den Dateinamen als Zeichenfolge enthält. Die gesamte E / A-Logik konzentrierte sich auf eine IFileSystem-Schnittstelle. Das Problem, das ich habe, ist, dass es immer noch wie ein ganzer Arbeitstag wäre, das gefälschte Dateisystem so zu implementieren, wie ich es brauchte (mit Unterstützung für Dateien + Ordner + versteckte Dateien + Umbenennen + nur den Pfad von einem Dateinamen abrufen + ...) und testen, um zu wissen, dass es tatsächlich richtig ist.
verschlang Elysium
1
Da Sie Ruby im OP erwähnt haben, möchte ich hier nur hinzufügen, dass es in C # auch ein Äquivalent gibt, System.IO.Abstractions, das ich kürzlich verwendet habe und das ziemlich gut ist.
Julealgon

Antworten:

52

Google verfügt über eine Open-Source-In-Memory-Implementierung des FileSystemProvider von Java 7. Das Projekt heißt jimfs .


Wenn Sie Java 6 oder früher verwenden, gibt es eine Alternative: Ich habe Apache Commons VFS bereits mit großem Erfolg verwendet. Es scheint dem benutzerdefinierten FileSystemProvider, der in Java 7 erwähnt wird, sehr ähnlich zu sein.

Es ist mit mehreren Dateisystemimplementierungen vorinstalliert : Datei, RAM, S / FTP und Jar, um nur einige zu nennen. Ich habe auch ein Plugin für S3 gesehen .

Michael Deardeuff
quelle
6
+1 auf jimfs, wodurch ich meinen Code ohne eine einzige Änderung testen konnte. (Ich habe Pathversehentlich verwendet)
user1071136
35

In Java 6 und früheren Versionen ist dies schwierig, da Klassen den Versand an verschiedene "virtuelle Dateisysteme" im Java-Bereich mögen Fileund FileInputStreamnicht ermöglichen.

In Java 7 werden virtuelle Dateisysteme unterstützt. Siehe Entwickeln eines benutzerdefinierten Dateisystemanbieters . Ich weiß nicht, ob Sie damit tun können, was Sie wollen, aber es ist ein guter Ort, um zu suchen.


Meh. Da es anscheinend kein gefälschtes Dateisystem gibt, werde ich wahrscheinlich nur eine minimale Implementierung selbst implementieren. Ich gewinne nichts mit FileSystemProvider

Tatsächlich gewinnen Sie mit FileSystemProvider:

  • Sie implementieren etwas, das (wenn es unter einer Open Source-Lizenz veröffentlicht wird) für andere Personen in Ihrer Position und für andere Zwecke sehr nützlich sein kann.

  • Sie machen es sich leichter, wenn Sie zu einem FileSystemProvider wechseln, an dem gerade jemand anderes arbeitet.

Stephen C.
quelle
Interessant, aber wie es scheint, müsste ich das Dateisystem immer noch selbst implementieren, nicht so nützlich ;-(
verschlungenes Elysium
6
Zumindest können Sie das tun. Und wie Sie selbst sagten - "es wäre einfach einzurichten" .
Stephen C
Meh. Da es anscheinend kein gefälschtes Dateisystem gibt, werde ich wahrscheinlich nur eine minimale Implementierung selbst implementieren. Ich gewinne nichts mit FileSystemProvider.
verschlang Elysium
@devoured elysium - siehe mein Update.
Stephen C
2
+1 für die Empfehlung, eine Lösung zu schreiben und Open Source zu
erstellen
17

Sie können org.junit.rules.TemporaryFolderaus dem JUnit- Paket verwenden:

Mit der TemporaryFolder-Regel können Dateien und Ordner erstellt werden, die nach Abschluss der Testmethode (unabhängig davon, ob sie erfolgreich ist oder nicht) gelöscht werden:

Beispiel:

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

Alternativ können Sie das .toPath()Teil beenden :

final File filePath = testFolder.newFile("input.txt");
thomas.mc.work
quelle
TemporaryFolder ist nicht im Speicher.
Progonkpa
8

Sie können die Verwendung von abstrahieren, Fileindem Sie die Absicht verwenden, "irgendwo Daten zu schreiben", indem Sie Ihre API so ändern, dass sie a OutputStreamanstelle von a verwendet File, und dann die API a FileOutputStreamin Ihrem Produktionscode übergeben, aber a ByteArrayOutputStreamaus Ihren Tests übergeben. A ByteArrayOutputStreamist ein In-Memory-Stream, daher ist er sehr schnell und Sie können seinen Inhalt einfach mithilfe seiner Methoden überprüfen - er eignet sich perfekt zum Testen. Es gibt auch die entsprechenden, ByteArrayInputStreamwenn Sie Daten lesen möchten .

Dateisysteme sind im Allgemeinen ziemlich schnell - wenn Sie in Ihren Tests nicht viel Datei-E / A ausgeführt haben, würde ich mich nicht darum kümmern.

Beachten Sie, dass eine Java - Erstellung FileObjekts nicht eine Datei auf der Festplatte erstellen, dh der folgende Code verursacht keine Änderung auf der Festplatte:

File f = new File("somepath"); // doesn't create a file on disk
Böhmisch
quelle
Neue Datei ("etwas") erstellt keine Datei auf der Festplatte. Wenn Sie jedoch versuchen, fast alle Methoden auszuführen, wird das Dateisystem verwendet. Versuchen Sie neue Datei ("xyz"). GetAbsolutePath (), um zu sehen, was ich meine ..
verschlungen Elysium
1
Ich denke, die Leute gehen davon aus, dass mein Hauptanliegen die Geschwindigkeit ist. Es ist nicht.
verschlang Elysium
1
Ich finde, es ist immer eine gute Praxis, Ressourcen wie Dateisysteme zu abstrahieren (genauso wie Sie eine Datenzugriffsschicht in die Datenbank schreiben würden). Dies wird normalerweise erreicht, indem eine Schnittstelle und ein dünner Wrapper um die unterste Klasse geschrieben werden. Wenn Sie die Abhängigkeitsinjektion auf der höchsten Ebene Ihres Programms verwenden, können Sie ein Mock-Dateisystem (beachten Sie, dass es kein Mock-Framework verwenden muss, sondern nur eine "Dummy" -Implementierung der Schnittstelle) sehr einfach über Ihre Anwendung verbreiten.
WickyNilliams
@devouredelysium new File("xyz").getAbsolutePath()macht absolut nichts, außer den Pfad zurückzugeben, den die Datei haben würde , wenn sie existieren würde. Das Dateisystem wird nicht geändert. Wenn die Datei nicht vorhanden ist, gibt sie dennoch die Zeichenfolge des Pfads zurück und erstellt keine Datei. Was meinten Sie mit "sehen, was passiert"?
Bohemian
1
Fileist nicht endgültig in meinem OpenJDK 7.
Dzmitry Lazerka
6

Jimfs von Google ist ein In-Memory-NIO-Dateisystem, das sich hervorragend für Tests eignet.

pron
quelle
4

Eine einfache Möglichkeit wäre, die Methode Ihres Systems zu verwenden, um ein Dateisystem bereitzustellen , das vollständig auf RAM basiert - tempfs unter Linux, eine RAM-Disk unter Windows.

Paŭlo Ebermann
quelle
Ich sehe nicht ein, wie das besser wäre, als das echte Dateisystem (außer Geschwindigkeit) zu verwenden.
verschlang Elysium
Ja, Geschwindigkeit (und Festplattenverschleiß) wären der Hauptgrund. Entschuldigung, vielleicht habe ich Ihr Ziel falsch verstanden.
Paŭlo Ebermann
1
Mein Ziel ist es, meine Tests zu vereinfachen. Ich beschäftige mich derzeit nicht mit Leistung.
verschlang Elysium
4

MockFTPServer scheint einige gefälschte Dateisystemimplementierungen zu haben (Unix / Windows)

Es sieht so aus, als könnten Sie diese gefälschten Dateisystemimplementierungen ganz getrennt von allen FTP-Konzepten verwenden. Ich versuche dies jetzt aus genau den gleichen Gründen, die Sie skizziert haben.

Deano
quelle
Ich verwende UnixFakeFileSystem. Funktioniert sehr gut als gefälschte Implementierung für meine FileSystem-Abstraktion.
Deano
2

Ich bin mir nicht sicher über bestimmte Frameworks, aber ein allgemeiner Ansatz in Bezug auf OOP wäre, einige abstrahierte Ebenen über jeden Dateizugriffscode (Schnittstellen in Hülle und Fülle!) und möglicherweise eine Fassade zu schreiben, um die Verwendung gängiger Operationen zu vereinfachen. Dann verspotten Sie nur eine Ebene unter dem Code, den Sie gerade testen, und es handelt sich dann im Wesentlichen um ein gefälschtes Dateisystem (oder zumindest der Code, den Sie testen, weiß nichts anderes).

Wenn Sie ein Abhängigkeitsinjektionsframework verwenden möchten, um dies für Sie zu erledigen, wird es die Möglichkeit erleichtern, Komponenten für eine gefälschte Implementierung einer Schnittstelle auszutauschen. Wenn Sie den Mustern der Umkehrung der Steuerung folgen und Abhängigkeiten an den Konstruktor der Klasse übergeben, die Sie testen, wird dies auch zum einfachen Testen.

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
   }
}

Ich hoffe, mein Java ist korrekt, ich habe Java schon lange nicht mehr geschrieben, aber Sie werden hoffentlich den Drift bekommen. hoffentlich unterschätze ich das Problem hier nicht und bin zu simpel!

Dies setzt natürlich voraus, dass Sie echte Unit-Tests meinen, dh das Testen der kleinstmöglichen Code-Einheiten und nicht eines ganzen Systems. Für Integrationstests ist ein anderer Ansatz erforderlich.

WickyNilliams
quelle
1
Ein gefälschtes Dateisystem muss eine eigene Logik haben - es ist ein Dateisystem wie jedes andere, aber das existiert nur im Speicher. Ich möchte vermeiden, dass ich mir ein solches Dateisystem programmieren muss.
verschlang Elysium
Welche Art von Dateisystemoperationen möchten Sie imitieren? Dateien sperren? lesen Schreiben? oder einfache Dinge wie das Öffnen von Dateien, das Überprüfen von Verzeichnissen, das Erstellen von Dateien?
WickyNilliams
Meist einfache Vorgänge, bei denen überprüft wird, ob es sich bei den Dateien um Dateien oder Verzeichnisse handelt, um Dateien zu erstellen und Dateien zu löschen. Dies unterstützt natürlich mehrere Ordner und Operationen wie "Abrufen des Pfads von diesem Dateinamen", "
Abrufen
Ich denke, wie ich bereits sagte, eine Abskription rund um das physische Dateisystem zu erstellen und diese (immer gegen die Schnittstelle codierend) immer in Ihrer App zu verwenden. Verwenden Sie dann einfach die Abhängigkeitsinjektion, um sich durch Ihre Testperson zu verbreiten. Ich weiß, dass es eintönige Arbeit ist, aber als Programmierer müssen wir diese Dinge tun, um eine saubere Trennung der Bedenken zu erreichen und eine einfache Testbarkeit zu ermöglichen :)
WickyNilliams
Sie bekommen wirklich nicht, was hier gefragt wird. Wenn ich nach einem gefälschten Dateisystem suche, muss dies daran liegen, dass ich bereits eine Abstraktion des gesamten Dateisystems in meiner App vorgenommen habe (wie in einem Kommentar des OP angegeben). Ich brauche nur eine gefälschte Implementierung des Dateisystems, um sie in meinen Tests zu verwenden.
verschlang Elysium
2

ShrinkWrap aus dem Arquillian-Projekt scheint ein NIO-kompatibles Speicher-Dateisystem zu enthalten

Sie können ein einfaches Dateisystem im Speicher erstellen, indem Sie folgende Schritte ausführen:

FileSystem fs = ShrinkWrapFileSystems.newFileSystem(ShrinkWrap.create(GenericArchive.class))
Rob Oxspring
quelle
Unterstützt es file: // Protokoll, kann keine Dokumentation finden ....
Marco Vasapollo
1

Zwei andere in Speicherdateisystemen für Java sind:

Speicher-Dateisystem

Ephemeralfs

Beide implementieren die NIO.2-Dateisystem-API.

meistens fremd
quelle
0

Ich habe "Fake java FileSystem" gegoogelt und diese Frage gefunden. Leider ist das alles was ich gefunden habe. Also habe ich dieses gefälschte Dateisystem selbst geschrieben: https://github.com/dernasherbrezon/mockfs

Ich verwende es zur Simulation von IOExceptions beim Lesen / Schreiben in Dateien. Eine IOException kann beispielsweise aufgrund von "kein Speicherplatz" auftreten, was mit anderen Mitteln kaum zu simulieren ist.

Andrey Rodionov
quelle