Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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 existsWorks everywhere: Windows, Linux, CI
Files from the previous run can affect the resultEvery test starts with an empty folder
Two tests running in parallel can overwrite each otherEach test has its own folder
Garbage stays on the diskThe 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.String

Declare the field as Path. If you need a string, call dir.toString().

Thanks for reading!

Donate to the site — we work hard for you.