JUnit 5 @TempDir Example: Temp Directory / File Support

Sometimes tests require temporary directories and files for performing intermediate test steps. JUnit 5 provides the @TempDir annotation that supplies a temporary directory to the test method or lifecycle methods.

1. JUnit @TempDir Annotation

JUnit Jupiter provides an extension model that allows us to extend the behavior of the test classes. One of the built-in extensions is the TempDirectoryExtension, which is designed for managing temporary directories during tests.

The TempDirectoryExtension is registered by default so we don’t need to explicitly configure or enable it.

To use the TempDirectoryExtension, we must annotate a field or method parameter in the test class with @TempDir. When JUnit Jupiter runs the test class, it detects this annotation and provides the annotated field with a temporary directory.

public class MyTestClass {

	@TempDir
	File tempDirectory;

	@Test
	public void testTemporaryFolder() throws IOException {

		assertTrue(Files.isDirectory(tempDir));

		Path createdFile = Files.createFile(
			tempDir.resolve("createdFile.txt")
		);

		assertTrue(createdFile.toFile().exists());
	}
}

In JUnit 4, we had the same support for temporary folders and files using the TemporaryFolder class annotated with @Rule.

public static class AppTest {

  @Rule
  public TemporaryFolder folder= new TemporaryFolder();

  @Test
  public void testUsingTempFolder() throws IOException {
  
    File createdFile = folder.newFile("myfile.txt");
    File createdFolder = folder.newFolder("subfolder");
    // ...
  }
}

2. How to use @TempDir in Tests?

2.1. Annotating the Field or Method Parameter

We can use the @TempDir in two ways:

  1. Annotate a non-final and unassigned field of type java.nio.file.Path or java.io.File with @TempDir.
public class TempDirExample {

    @TempDir
    private File tempDirectory;

    //or

    @TempDir
    private Path tempDirectoryPath;

    //...
 }
  1. Annotate a method parameter of type java.nio.file.Path or java.io.File with @TempDir.
public class TempDirExample {

	@Test
	void testMethod(@TempDir File tempDir) throws IOException {
		//...
	}

	//or

	@Test
	void testMethod(@TempDir Path tempDirPath) throws IOException {
		//...
	}
}

We may get the following errors if we do not follow the rules:

  • If we try to use @TempDir with a different type, then an org.junit.jupiter.api.extension.ParameterResolutionException will be thrown.
  • If the temporary directory cannot be created for some reason, an ExtensionConfigurationException will be thrown.

2.2. Can’t be used as a Constructor Argument

@TempDir is not supported on constructor parameters. A ParameterResolutionException will be thrown for a constructor parameter annotated with it.

public class MyTestClass {

  File tempDirectory;

  public MyTestClass(@TempDir File tempDirectory) {

  	this.tempDirectory = tempDirectory;	// throws ParameterResolutionException
  }
}

2.3. Location of Temp Directory

Internally the JUnit uses Files.createTempDirectory() method for creating the temporary directory in the system. Most likely, the createTempDirectory() method then makes use of the default system temporary file directory. The details of how the directory’s name is constructed are implementation-dependent and therefore not specified.

Here are the typical locations for the temporary directory on common operating systems:

  • On Windows, the temporary directory is typically located at ‘C:\Users\<Username>\AppData\Local\Temp‘.
  • On macOS, the temporary directory is usually located at ‘/var/folders/‘.
  • On Linux, the temporary directory is commonly located at ‘/tmp‘.

3. Sharing a Temporary Directory across Tests

All tests in a class will share the temporary directory when the annotation is present on a static field or on a parameter of a @BeforeAll method.

This is an example of using @TempDir on a static field.

@TempDir
static Path tempDir;

Similarly, we can annotate a @BeforeAll method and use its reference in other tests to access the temporary folder.

static Path tempDir;

@BeforeAll
static void setup(@TempDir Path tempDirParam) throws IOException {
    tempDir = tempDirParam;
}

@Test
void anotherTestWithTempDir() {
    // A test that can use the 'tempDir' directory created in setup().
}

When @TempDir is only used on instance fields or on parameters in test, @BeforeEach, or @AfterEach methods — each test will use its own temporary directory.

@TempDir
Path tempDir;

//or

Path tempDir;

@BeforeEach
void setup(@TempDir Path tempDirParam) throws IOException {
    this.tempDir = tempDirParam;
}

@Test
void anotherTestWithTempDir() {
    // A test that can use the 'tempDir' directory created in setup().
}

4. Cleaning Up a Temp Directory

Before JUnit 5.9, when the test method or class has finished execution, JUnit will attempt to recursively delete all files and directories in the temporary directory and, finally, the temporary directory itself.

The test will fail with an IOException if there is any error in deleting any temporary file or directory.

Starting JUnit 5.9, it allows for specifying the cleanup policy via the CleanupMode enum constants:

  • ALWAYS: Always clean up a temporary directory after the test has been completed.
  • DEFAULT: Use the default cleanup mode. CleanupMode.ALWAYS is the default cleanup policy.
  • NEVER: Never clean up a temporary directory after the test has been completed.
  • ON_SUCCESS: Only clean up a temporary directory if the test is completed successfully.
@TempDir(cleanup = CleanupMode.ON_SUCCESS)

5. @TempDir Examples

5.1. @TempDir as Test Method Argument

This approach is helpful when there is only a single test method where we need to take the help of a temporary file. We can directly pass the path to the temp file into the test method.

In the given test, we are writing some content to a file test.txt in a temporary file. Then we reread the same file to match the file’s content with what we had written.

We are creating the text file as a temporary file which will get deleted after the test execution is complete.

Notice the tempDir parameter to the test. It is of type java.nio.file.Path and annotated with @TempDir.

@Test
void tempDirectoryTestOne(@TempDir Path tempDir) throws IOException 
{
	Path tempFile = tempDir.resolve("test.txt");

	List<String> lines = Arrays.asList("howtodoinjava.com");

	Files.write(tempFile, Arrays.asList("howtodoinjava.com"));

	Assertions.assertTrue(Files.exists(tempFile), "Temp File should have been created");
	Assertions.assertEquals(Files.readAllLines(tempFile), lines);
}

5.2. @TempDir as Instance Field

We can use this approach if we need to access the temporary file in more than one test method. When using an instance field, each test creates a new temporary file and deletes it after the test execution is complete.

For example, we are rewriting the first example. Both tests will create a new temporary file for them and delete it afterward.

@TempDir
Path tempDir;

@Test
void tempDirectoryTestOne() throws IOException {
	
	Path tempFile = tempDir.resolve("test.txt");

	List<String> lines = Arrays.asList("howtodoinjava.com");

	Files.write(tempFile, Arrays.asList("howtodoinjava.com"));

	Assertions.assertTrue(Files.exists(tempFile), "Temp File should have been created");
	Assertions.assertEquals(Files.readAllLines(tempFile), lines);
}

@Test
void tempDirectoryTestTwo() throws IOException {
	
	Path tempFile = tempDir.resolve("test2.txt"); 
	//Test code
}

5.3. @TempDir as Static Instance Field

This is not recommended but if we want to share the temporary file between multiple test methods.

@TempDir
static Path tempDir;

@Test
void tempDirectoryTestOne() throws IOException {
	
	Path tempFile = tempDir.resolve("test.txt");

	//create new temporary file
}

@Test
void tempDirectoryTestTwo() throws IOException {
	
	Path tempFile = tempDir.resolve("test.txt"); 
	
	//Reuses the same temporary file created by previous test
}

6. Best Practices

  • If you want to copy some files into the temp directory before the test execution, you would typically do that in a @BeforeAll or @BeforeEach method in the test class.
@BeforeEach
void setup(@TempDir Path tempDir) throws IOException 
{
	Path tempFile = tempDir.resolve("test.txt");
	Files.write(tempFile, Arrays.asList("some content"));
}
  • Use static modifier with @TempDir annotated field if the same temporary file has to be shared between all the tests.
  • In this case, use @Order annotation to enforce the test order and ensure the behavior is consistent.

Happy Learning !!

Comments

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode