Temporary files: @TempDir
Code that works with files is awkward to test: where to write, how to clean up, what if two tests write the same file at once? JUnit solves this with the @TempDir annotation. Before the test it creates an empty temporary folder, passes its path to the test and deletes it with all contents afterwards.
The class under test
The blog exports posts to a CSV file. Create src/main/java/com/example/blog/PostExporter.java:
// src/main/java/com/example/blog/PostExporter.java
package com.example.blog;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
public class PostExporter {
public void exportCsv(List<Post> posts, Path file) throws IOException {
List<String> lines = posts.stream()
.map(p -> p.id() + ";" + p.title() + ";" + p.author())
.toList();
Files.write(file, lines);
}
}The method takes the path to the file as a parameter — that is what makes it easy to test: the test decides where the file goes.
@TempDir on a field
// src/test/java/com/example/blog/PostExporterTest.java
package com.example.blog;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
class PostExporterTest {
@TempDir
Path dir;
@Test
void writesOneLinePerPost() throws IOException {
Path file = dir.resolve("posts.csv");
List<Post> posts = List.of(
new Post(1L, "Hello, JUnit", "anna", true),
new Post(2L, "Mockito basics", "oleg", false)
);
new PostExporter().exportCsv(posts, file);
assertEquals(List.of("1;Hello, JUnit;anna", "2;Mockito basics;oleg"),
Files.readAllLines(file));
}
}dir is a fresh empty folder for every test, somewhere in the system temporary directory. dir.resolve("posts.csv") builds the path of a file inside it. The test writes the file, reads it back and compares the lines. A test method may declare throws IOException — an unexpected exception simply fails the test.
@TempDir on a parameter
The folder can also be requested as a test parameter:
// src/test/java/com/example/blog/PostExporterTest.java
@Test
void emptyListGivesEmptyFile(@TempDir Path other) throws IOException {
Path file = other.resolve("empty.csv");
new PostExporter().exportCsv(List.of(), file);
assertEquals(0, Files.size(file));
}This is convenient when only one test in the class needs files.
Why not just "C:/tmp"
| Fixed path | @TempDir |
|---|---|
| Works only on the machine where the folder exists | Works everywhere: Windows, Linux, CI |
| Files from the previous run can affect the result | Every test starts with an empty folder |
| Two tests running in parallel can overwrite each other | Each test has its own folder |
| Garbage stays on the disk | The folder is deleted after the test |
If you need to look at the file after a failure, add @TempDir(cleanup = CleanupMode.ON_SUCCESS): the folder is kept only when the test fails.
Common mistake
@TempDir works only with java.nio.file.Path and java.io.File. A field of type String is a configuration error:
@TempDir
String dir;org.junit.jupiter.api.extension.ExtensionConfigurationException: Can only resolve @TempDir field of type java.nio.file.Path or java.io.File but was: java.lang.StringDeclare the field as Path. If you need a string, call dir.toString().