Czy istnieją ramy fałszywego systemu plików dla języka Java? [Zamknięte]

84

Przedstawiam testy w projekcie, który intensywnie wykorzystuje operacje IO (w tym przypadku system plików). System stale otwiera / zamyka pliki, sprawdza, czy pliki istnieją, usuwa je itp.

Szybko stało się oczywiste, że regularne kpiny nie przydałyby się zbytnio, ponieważ utrudniłoby mi konfigurację testów i uzasadnienie. Z drugiej strony posiadanie fałszywego systemu plików byłoby niesamowite i myślę, że całkiem łatwe w konfiguracji.

Wygląda na to, że kolesie z Rubiego zrobili to ponownie i właśnie o to proszę w rubim: http://ozmm.org/posts/fakefs.html .

Czy jest coś zdalnie podobnego dla Javy?

pożarł elizjum
źródło
1
Wygląda na to, że poziom aplikacji jest łatwiejszy do wykonania w językach bez statycznego systemu typów. W Javie File / FileInputStream / FileOutputStream zawsze będzie odnosić się do systemu plików podstawowego systemu - jeśli nie załatasz maszyny wirtualnej.
Paŭlo Ebermann
Istnieją interfejsy, takie jak JavaFileManager lub FileSystemView, które można zaimplementować, ale większość programów ich nie używa.
Paŭlo Ebermann
@ 1 komentarz: Jestem tego świadomy. Obecnie zamieniłem wszystkie zastosowania pliku na własną nazwę pliku, która zawiera tylko nazwę pliku jako ciąg. Cała logika IO została skoncentrowana na interfejsie IFileSystem. Problem, który mam, polega na tym, że wdrożenie fałszywego systemu plików tak, jak tego potrzebowałem, trwałoby cały dzień pracy (z obsługą plików + folderów + ukrytych plików + zmiany nazw + pobieranie tylko ścieżki z nazwy pliku + ...) i przetestować go, aby wiedzieć, że rzeczywiście ma rację.
pożarł elysium
1
Skoro wspomniałeś o Rubim w OP, chciałbym tylko dodać, że w C # jest również odpowiednik System.IO.Abstractions, którego zacząłem używać niedawno i jest całkiem niezły.
julealgon

Odpowiedzi:

53

Google ma otwartą implementację w pamięci oprogramowania FileSystemProvider Java 7. Projekt nazywa jimfs .


Jeśli używasz Java 6 lub wcześniejszej, istnieje alternatywa: wcześniej używałem Apache Commons VFS, aby osiągnąć wielki sukces. Wygląda na to, że jest bardzo podobny do niestandardowego FileSystemProvider, inny wspomniany odpowiadający jest w Javie 7.

Jest wstępnie załadowany z kilkoma implementacjami systemu plików: Plik, RAM, S / FTP i Jar, aby wymienić tylko kilka. Widziałem też wtyczkę dla S3 .

Michael Deardeuff
źródło
6
+1 do jimfs, co pozwoliło mi przetestować mój kod bez jednej zmiany. (Użyłem Pathprzypadkowo)
user1071136
36

W Javie 6 i wcześniejszych jest to trudne, ponieważ klasy takie jak Filei FileInputStreamnie zapewniają możliwości wysyłania do różnych „wirtualnych systemów plików” w przestrzeni Java.

W Javie 7 dostępna jest obsługa wirtualnych systemów plików; zobacz Tworzenie niestandardowego dostawcy systemu plików . Nie wiem, czy to pozwoli ci robić to, co chcesz, ale to dobre miejsce, aby zacząć szukać.


Meh. Ponieważ wydaje się, że nie ma żadnego fałszywego systemu plików, myślę, że sam zaimplementuję minimalną implementację. Nic nie wygrywam, używając FileSystemProvider

Właściwie wygrywasz używając FileSystemProvider:

  • Wdrażasz coś, co (jeśli jest wydane na licencji open source) może być bardzo przydatne dla innych osób na twoim stanowisku i do innych celów.

  • Ułatwisz sobie to, jeśli zdecydujesz się przełączyć na dostawcę FileSystemProvider, nad którym może teraz pracować ktoś inny.

Stephen C.
źródło
Ciekawe, ale jak się wydaje, nadal musiałbym zaimplementować system plików samodzielnie, niezbyt przydatny ;-(
pożarł elysium
7
Przynajmniej pozwala ci to zrobić. I jak sam powiedziałeś - „byłoby to łatwe w konfiguracji” .
Stephen C
Meh. Ponieważ wydaje się, że nie ma żadnego fałszywego systemu plików, myślę, że sam zaimplementuję minimalną implementację. Nic nie wygrywam, używając FileSystemProvider.
pożarł elysium
@devoured elysium - zobacz moją aktualizację.
Stephen C
2
+1 za rekomendowanie pisania i open source-
owanie
19

Możesz użyć org.junit.rules.TemporaryFolderz pakietu JUnit :

Reguła TemporaryFolder umożliwia tworzenie plików i folderów, które mają zostać usunięte po zakończeniu metody testowej (niezależnie od tego, czy zakończy się ona pomyślnie, czy nie):

Przykład:

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

Alternatywnie zrezygnuj z .toPath()części:

final File filePath = testFolder.newFile("input.txt");
thomas.mc.work
źródło
TemporaryFolder nie znajduje się w pamięci.
progonkpa
8

Możesz wyodrębnić użycie programu File, używając zamiaru „gdzieś do zapisu danych”, zmieniając interfejs API tak, aby używał OutputStreamzamiast a File, a następnie przekazać API a FileOutputStreamw kodzie produkcyjnym, ale przekaż je ByteArrayOutputStreamz testów. A ByteArrayOutputStreamjest strumieniem w pamięci, więc jest bardzo szybki i możesz po prostu sprawdzić jego zawartość za pomocą jego metod - jest idealny do testowania. Jest też odpowiedni, ByteArrayInputStreamjeśli chcesz odczytać dane.

Systemy plików są generalnie dość szybkie - nie zawracałbym sobie tym głowy, chyba że robisz dużo operacji we / wy plików w swoich testach.

Należy pamiętać, że tworzenie java Fileobiekt ma nie utworzyć plik na dysku, to poniższy kod nie powoduje żadnych zmian na dysku:

File f = new File("somepath"); // doesn't create a file on disk
Czeski
źródło
new File („coś”) nie utworzy pliku na dysku, ale jeśli spróbujesz uruchomić prawie którąkolwiek z jego metod, użyje systemu plików. Wypróbuj nowy plik ( "xyz") getAbsolutePath (), aby zobaczyć, co mam na myśli ...
pożarł Elysium
1
Myślę, że ludzie zakładają, że moim głównym zmartwieniem jest szybkość. Nie jest.
pożarł elizjum
1
Uważam, że zawsze dobrą praktyką jest wyodrębnienie wszelkich zasobów, takich jak systemy plików (w taki sam sposób, jak zapisuje się warstwę dostępu do danych w bazie danych). zwykle osiąga się to poprzez napisanie interfejsu i cienkiej otoczki wokół klasy najniższego poziomu. jeśli używasz iniekcji zależności na najwyższym poziomie swojego programu, możesz bardzo łatwo propagować fałszywy system plików (pamiętaj, że nie musi on używać pozorowanego frameworka, tylko "fikcyjną" implementację interfejsu) przez twoją aplikację.
WickyNilliams
@devouredelysium new File("xyz").getAbsolutePath()ma absolutnie nic wspólnego except powrócić na ścieżkę, że plik będzie mieć gdyby istniał. Nie zmienia systemu plików; jeśli plik nie istnieje, nadal zwraca ciąg ścieżki i nie tworzy pliku. Co miałeś na myśli mówiąc „zobacz, co się stanie”?
Bohemian
1
Filenie jest ostateczna w moim OpenJDK 7.
Dzmitry Lazerka
4

Prostym sposobem byłoby użycie systemu plików opartego całkowicie na pamięci RAM - tempfs w systemie Linux, dysk RAM w systemie Windows.

Paŭlo Ebermann
źródło
Nie widzę, żeby to było lepsze niż użycie prawdziwego systemu plików (innego niż szybkość).
pożarł elizjum
Tak, głównym powodem byłaby prędkość (i zużycie dysku). Przepraszam, może źle zrozumiałem twój cel.
Paŭlo Ebermann
1
Moim celem jest ułatwienie mi testowania. Obecnie nie interesuje mnie wydajność.
pożarł elizjum
4

Wygląda na to, że MockFTPServer ma kilka implementacji fałszywego systemu plików (Unix / Windows)

Wygląda na to, że możesz używać tych fałszywych implementacji systemu plików całkiem oddzielnie od wszelkich koncepcji FTP. Próbuję tego teraz w dokładnie tych samych celach, które opisałeś.

Deano
źródło
Używam UnixFakeFileSystem. Działa bardzo dobrze jako fałszywa implementacja dla mojej abstrakcji FileSystem.
Deano,
2

Nie jestem pewien co do konkretnych frameworków, ale ogólnym podejściem w zakresie OOP byłoby napisanie kilku abstrakcyjnych warstw na wierzchu dowolnego kodu dostępu do pliku (bród interfejsów!) i być może fasadę ułatwiającą korzystanie z typowych operacji. następnie po prostu mockujesz jedną warstwę poniżej kodu, który aktualnie testujesz, i jest to zasadniczo fałszywy system plików (a przynajmniej kod, który testujesz, nie będzie wiedział inaczej).

Jeśli przyjrzysz się użyciu struktury iniekcji zależności, aby poradzić sobie z tym za Ciebie, ułatwi to możliwość przełączania komponentów na fałszywą implementację interfejsu. Jeśli zastosujesz się do wzorców odwrócenia kontroli, przekazanie wszelkich zależności do konstruktora klasy, którą testujesz, również ułatwi testowanie.

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

Mam nadzieję, że moja java jest poprawna, nie pisałem javy przez długi czas, ale mam nadzieję, że zrozumiesz dryf. mam nadzieję, że nie lekceważę tego problemu i jestem zbyt uproszczony!

oczywiście to wszystko przy założeniu, że masz na myśli prawdziwe testowanie jednostkowe, to znaczy testowanie najmniejszych możliwych jednostek kodu, a nie całego systemu. do testowania integracji potrzebne jest inne podejście.

WickyNilliams
źródło
1
Fałszywy system plików musi mieć własną logikę - jest to system plików jak każdy inny, ale istnieje tylko w pamięci. Chciałbym uniknąć konieczności samodzielnego programowania takiego systemu plików.
pożarł elysium
jaki typ operacji systemu plików chcesz naśladować? blokowanie plików? czytać / pisać? lub proste rzeczy, takie jak otwieranie plików, sprawdzanie katalogów, tworzenie plików?
WickyNilliams
Przeważnie proste operacje, które zajmują się sprawdzaniem, czy pliki są plikami lub katalogami, jeśli istnieją, tworzeniem plików, usuwaniem plików. To, oczywiście, przy jednoczesnym wspieraniu wielu folderów i operacje takie jak „dostać drogę od tego pliku”, „uzyskać względną ścieżkę od ścieżki bezwzględnej”, itd.
pożarł Elysium
myślę, jak już powiedziałem, tworząc absrtakcję wokół fizycznego systemu plików i zawsze używam tego (zawsze kodując w interfejsie) w całej aplikacji. następnie po prostu użyj zastrzyku zależności, aby rozpropagować swój obiekt testu. Wiem, że to monotonna praca, ale jak programiści musieli robić te rzeczy, aby uzyskać czystą separacji obawy i pozwalają na łatwość testowalności :)
WickyNilliams
Naprawdę nie otrzymujesz tego, o co tutaj proszono. Jeśli szukam fałszywego systemu plików, musi to być spowodowane tym, że zrobiłem już abstrakcję całego systemu plików w mojej aplikacji (jak stwierdzono w komentarzu do OP). Ja po prostu potrzebuję realizacji fałszywego systemu plików do wykorzystania w moich testach ..
pożarł Elysium
2

Wygląda na to, że ShrinkWrap z projektu Arquillian zawiera w pamięci FileSystem zgodny z NIO

Możesz utworzyć prosty system plików w pamięci, wykonując następujące czynności:

FileSystem fs = ShrinkWrapFileSystems.newFileSystem(ShrinkWrap.create(GenericArchive.class))
Rob Oxspring
źródło
Czy obsługuje protokół file: //, nie można znaleźć dokumentacji ...
Marco Vasapollo
1

Dwa inne systemy plików pamięci dla Java to:

system plików pamięci

efemeralfy

Oba implementują interfejs API systemu plików NIO.2.

przeważnie obcy
źródło
0

Wyszukałem w Google „Fake java FileSystem” i znalazłem to pytanie. Niestety to wszystko, co znalazłem. Więc sam napisałem ten fałszywy system plików: https://github.com/dernasherbrezon/mockfs

Używam go do symulacji IOExceptions podczas odczytu / zapisu do plików. IOException może wystąpić na przykład z powodu „braku miejsca na dysku”, co jest prawie niemożliwe do zasymulowania innymi sposobami.

Andrey Rodionov
źródło