„Die Erinnerung darf nicht enden; sie muss auch künftige Generationen zur Wachsamkeit mahnen. Es ist deshalb wichtig, nun eine Form des Erinnerns zu finden, die in die Zukunft wirkt.“
Bundespräsident Roman Herzog
While implementing some tests for the Freshmarker 1.0.0 release, I discovered another interesting possibility for a JUnit 5 TempDirFactory
implementation. But first things first.
The JUnit 5 TempDirFactory
is a mechanism to create your own temp directories for JUnit 5 tests. Normally, the @TempDir
annotation is used to obtain a File
or Path
instance that refers to a system-specific temp directory.
@Test void test(@TempDir Path folder) { Files.writeString(folder.resolve("test.txt", "Hello World"); // ... }
The test uses the temp directory folder
to create a file in it. At the end of the test, the directory is usually deleted automatically.
In the article Custom Temp Folders in JUnit 5, a custom TempDirFactory
was implemented that created temp directories in the Maven target
directory. However, the new TemplDirFactory
implementation should not use a different directory, but a different file system.
Before Java 7, a file instance was directly assigned to a file or a directory in the native file system. Since Java 7, it is possible to use other file systems in addition to the standard file system. With the introduction of Java NIO, developers can use Path
instances to access files that are not located in the native file system, but somewhere else.
Unfortunately, there are very few implementations of a FileSystem
outside of the standard libraries. In addition to the standard FileSystem
implementations for the native file systems of the various operating systems, there is also the ZipFileSystem
, which can be used to open an archive file as a separate file system.
A well-known Java file system outside the standard libraries is Jimfs from Google. It is an in-memory file system that keeps all data, unsurprisingly, in memory. The advantage of such a file system is its speed, because no hard disc accesses are required. The disadvantage is that no data is persisted, it only exists during the runtime of the application.
To work with Jimfs, we first need the library as a dependency in our project.
<dependency> <groupId>com.google.jimfs</groupId> <artifactId>jimfs</artifactId> <version>${jimfs.version}</version> </dependency>
A custom TempDirFactory
that uses the Jimfs is very easy to implement.
public class InMemoryTempDirFactory implements TempDirFactory { private final Path root; public InMemoryTempDirFactory() { FileSystem fileSystem = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix()); root = fileSystem.getPath("/"); } @Override public Path createTempDirectory(AnnotatedElementContext elementContext, ExtensionContext extensionContext) throws Exception { return Files.createTempDirectory(root, "junit"); } }
A Jimfs file system and a path instance for the root
directory are created in the constructor. In the createTempDirectory
, a temp directory with the prefix junit
is then always created in the root
directory.
With a small change, our example unit test no longer writes the file to the native file system but to an in-memory file system.
@Test void test(@TempDir(factory=de.schegge.test.InMemoryTempDirFactory.class) Path folder) { Files.writeString(folder.resolve("test.txt", "Hello World"); // ... }
The only necessary change is the factory
attribute with our own InMemoryTempDirFactory
at the @TempDir
annotation.
If you would like to try out the InMemoryTempDirFactory
for yourself, you can find it as part of the junit-5-gimmicks on Maven Central.
<dependency> <groupId>de.schegge</groupId> <artifactId>junit-5-gimmicks</artifactId> <version>0.2.0</version> </dependency>