Bestandssysteem bespotten met Jimfs

1. Overzicht

Bij het testen van componenten die veel gebruik maken van I / O-bewerkingen, kunnen onze tests verschillende problemen ondervinden, zoals slechte prestaties, platformafhankelijkheid en onverwachte toestand.

In deze tutorial we zullen bekijken hoe we deze problemen kunnen verlichten met behulp van het in-memory bestandssysteem Jimfs.

2. Inleiding tot Jimfs

Jimfs is een bestandssysteem in het geheugen dat de Java NIO API implementeert en ondersteunt bijna elk kenmerk ervan. Dit is vooral handig, omdat het betekent dat we een virtueel bestandssysteem in het geheugen kunnen emuleren en ermee kunnen communiceren met behulp van ons bestaande java.nio laag.

Zoals we zullen zien, kan het nuttig zijn om een ​​bespotten bestandssysteem te gebruiken in plaats van een echt om:

  • Voorkom dat u afhankelijk bent van het bestandssysteem waarop de test momenteel wordt uitgevoerd
  • Zorg ervoor dat het bestandssysteem bij elke testrun wordt samengesteld met de verwachte status
  • Help onze tests te versnellen

Omdat bestandssystemen aanzienlijk verschillen, maakt het gebruik van Jimfs ook gemakkelijk testen met bestandssystemen van verschillende besturingssystemen mogelijk.

3. Maven afhankelijkheden

Laten we eerst de projectafhankelijkheden toevoegen die we nodig hebben voor onze voorbeelden:

 com.google.jimfs jimfs 1.1 

De jimfs-afhankelijkheid bevat alles wat we nodig hebben om ons bespotte bestandssysteem te gebruiken. Bovendien zullen we tests schrijven met JUnit5.

4. Een eenvoudige bestandsrepository

We beginnen met het definiëren van een eenvoudig FileRepository klasse die enkele standaard CRUD-bewerkingen implementeert:

openbare klasse FileRepository {void create (Path path, String fileName) {Path filePath = path.resolve (fileName); probeer {Files.createFile (filePath); } catch (IOException ex) {throw new UncheckedIOException (ex); }} String read (Path path) {probeer {return new String (Files.readAllBytes (path)); } catch (IOException ex) {throw new UncheckedIOException (ex); }} String update (Path path, String newContent) {probeer {Files.write (path, newContent.getBytes ()); retourneer newContent; } catch (IOException ex) {throw new UncheckedIOException (ex); }} void delete (Path path) {probeer {Files.deleteIfExists (path); } catch (IOException ex) {throw new UncheckedIOException (ex); }}}

Zoals we kunnen zien, maakt elke methode gebruik van standaard java.nio klassen.

4.1. Een bestand aanmaken

In deze sectie zullen we een test schrijven die de creëren methode uit onze repository:

@Test @DisplayName ("Moet een bestand op een bestandssysteem maken") ongeldig gegevenUnixSystem_whenCreatingFile_thenCreatedInPath () {FileSystem fileSystem = Jimfs.newFileSystem (Configuration.unix ()); String fileName = "newFile.txt"; Pad pathToStore = fileSystem.getPath (""); fileRepository.create (pathToStore, bestandsnaam); assertTrue (Files.exists (pathToStore.resolve (bestandsnaam))); }

In dit voorbeeld hebben we de statisch methode Jimfs.newFileSystem () om een ​​nieuw bestandssysteem in het geheugen te maken. We passeren een configuratie-object Configuratie.unix (), die een onveranderlijke configuratie creëert voor een Unix-bestandssysteem. Dit omvat belangrijke OS-specifieke informatie zoals padscheidingstekens en informatie over symbolische koppelingen.

Nu we een bestand hebben gemaakt, kunnen we controleren of het bestand met succes is gemaakt op het Unix-systeem.

4.2. Een bestand lezen

Vervolgens zullen we de methode testen die de inhoud van het bestand leest:

@Test @DisplayName ("Moet de inhoud van het bestand lezen") ongeldig gegeven OSXSystem_whenReadingFile_thenContentIsReturned () gooit uitzondering {FileSystem fileSystem = Jimfs.newFileSystem (Configuration.osX ()); Pad resourceFilePath = fileSystem.getPath (RESOURCE_FILE_NAME); Files.copy (getResourceFilePath (), resourceFilePath); String content = fileRepository.read (resourceFilePath); assertEquals (FILE_CONTENT, inhoud); }

Deze keer hebben we gecontroleerd of het mogelijk is om de inhoud van het bestand te lezen op een macOS (voorheen OSX) -systeem door simpelweg een ander type configuratie te gebruiken - Jimfs.newFileSystem (Configuration.osX ()).

4.3. Een bestand updaten

We kunnen Jimfs ook gebruiken om de methode te testen waarmee de inhoud van het bestand wordt bijgewerkt:

@Test @DisplayName ("Moet de inhoud van het bestand bijwerken") ongeldig gegevenWindowsSystem_whenUpdatingFile_thenContentHasChanged () gooit uitzondering {FileSystem fileSystem = Jimfs.newFileSystem (Configuration.windows ()); Pad resourceFilePath = fileSystem.getPath (RESOURCE_FILE_NAME); Files.copy (getResourceFilePath (), resourceFilePath); String newContent = "Ik ben je aan het updaten."; String content = fileRepository.update (resourceFilePath, newContent); assertEquals (newContent, content); assertEquals (newContent, fileRepository.read (resourceFilePath)); }

Evenzo hebben we deze keer gecontroleerd hoe de methode zich gedraagt ​​op een Windows-gebaseerd systeem met behulp van Jimfs.newFileSystem (Configuration.windows ()).

4.4. Een bestand verwijderen

Om het testen van onze CRUD-bewerkingen af ​​te ronden, laten we de methode testen waarmee het bestand wordt verwijderd:

@Test @DisplayName ("Moet bestand verwijderen") ongeldig gegevenCurrentSystem_whenDeletingFile_thenFileHasBeenDeleted () gooit uitzondering {FileSystem fileSystem = Jimfs.newFileSystem (); Pad resourceFilePath = fileSystem.getPath (RESOURCE_FILE_NAME); Files.copy (getResourceFilePath (), resourceFilePath); fileRepository.delete (resourceFilePath); assertFalse (Files.exists (resourceFilePath)); }

In tegenstelling tot eerdere voorbeelden hebben we Jimfs.newFileSystem () zonder een bestandssysteemconfiguratie op te geven. In dat geval zal Jimfs een nieuw bestandssysteem in het geheugen aanmaken met een standaardconfiguratie die past bij het huidige besturingssysteem.

5. Verplaatsen van een bestand

In dit gedeelte leren we hoe we een methode kunnen testen die een bestand van de ene map naar de andere verplaatst.

Laten we eerst het Actie methode met behulp van de standaard java.nio.file.File klasse:

void move (pad oorsprong, pad bestemming) {probeer {Files.createDirectories (bestemming); Files.move (oorsprong, bestemming, StandardCopyOption.REPLACE_EXISTING); } catch (IOException ex) {throw new UncheckedIOException (ex); }}

We gaan een geparametriseerde test gebruiken om ervoor te zorgen dat deze methode werkt op verschillende bestandssystemen:

private statische Stream offerFileSystem () {return Stream.of (Arguments.of (Jimfs.newFileSystem (Configuration.unix ())), Arguments.of (Jimfs.newFileSystem (Configuration.windows ())), Arguments.of (Jimfs. newFileSystem (Configuration.osX ()))); } @ParameterizedTest @DisplayName ("Moet bestand naar nieuwe bestemming verplaatsen") @MethodSource ("offerFileSystem") ongeldig gegevenEachSystem_whenMovingFile_thenMovedToNewPath (FileSystem fileSystem) gooit uitzondering {Path origin = fileSystem.getPath (RESOURCE_FILE_NAME); Files.copy (getResourceFilePath (), oorsprong); Padbestemming = fileSystem.getPath ("newDirectory", RESOURCE_FILE_NAME); fileManipulation.move (oorsprong, bestemming); assertFalse (Files.exists (oorsprong)); assertTrue (Files.exists (bestemming)); }

Zoals we kunnen zien, hebben we Jimfs ook kunnen gebruiken om te testen of we bestanden op verschillende bestandssystemen kunnen verplaatsen vanuit een enkele unit-test.

6. Besturingssysteemafhankelijke tests

Om een ​​ander voordeel van het gebruik van Jimfs te demonstreren, maken we een FilePathReader klasse. De klasse is verantwoordelijk voor het retourneren van het echte systeempad, dat natuurlijk OS-afhankelijk is:

klasse FilePathReader {String getSystemPath (padpad) {probeer {retourpad .toRealPath () .toString (); } catch (IOException ex) {throw new UncheckedIOException (ex); }}}

Laten we nu een test voor deze klas toevoegen:

klasse FilePathReaderUnitTest {privé statische String DIRECTORY_NAME = "baeldung"; private FilePathReader filePathReader = nieuwe FilePathReader (); @Test @DisplayName ("Moet pad op windows krijgen") ongeldig gegevenWindowsSystem_shouldGetPath_thenReturnWindowsPath () gooit uitzondering {FileSystem fileSystem = Jimfs.newFileSystem (Configuration.windows ()); Padpad = getPathToFile (fileSystem); String stringPath = filePathReader.getSystemPath (pad); assertEquals ("C: \ work \" + DIRECTORY_NAME, stringPath); } @Test @DisplayName ("Moet pad op unix krijgen") void givenUnixSystem_shouldGetPath_thenReturnUnixPath () gooit uitzondering {FileSystem fileSystem = Jimfs.newFileSystem (Configuration.unix ()); Padpad = getPathToFile (fileSystem); String stringPath = filePathReader.getSystemPath (pad); assertEquals ("/ work /" + DIRECTORY_NAME, stringPath); } privépad getPathToFile (FileSystem fileSystem) genereert uitzondering {Path path = fileSystem.getPath (DIRECTORY_NAME); Files.createDirectory (pad); terugweg; }}

Zoals we kunnen zien, verschilt de uitvoer voor Windows van die van Unix, zoals we zouden verwachten. Bovendien, we hoefden deze tests niet uit te voeren met twee verschillende bestandssystemen - Jimfs bespotte het automatisch voor ons.

Dat is het vermelden waard Jimfs ondersteunt het toFile () methode die een java.io.File. Het is de enige methode van de Pad klasse die niet wordt ondersteund. Daarom is het misschien beter om te opereren op een InputStream liever dan een het dossier.

7. Conclusie

In dit artikel hebben we geleerd hoe we het in-memory bestandssysteem Jimfs kunnen gebruiken om de interacties van het bestandssysteem uit onze unit tests te bespotten.

Ten eerste zijn we begonnen met het definiëren van een eenvoudige bestandsrepository met verschillende CRUD-bewerkingen. Toen zagen we voorbeelden van hoe we elk van de methoden konden testen met een ander type bestandssysteem. Ten slotte zagen we een voorbeeld van hoe we Jimfs kunnen gebruiken om de OS-afhankelijke verwerking van bestandssystemen te testen.

Zoals altijd is de code voor deze voorbeelden beschikbaar op Github.