eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

Course – LJU – NPI (tag = JUnit)
announcement - icon

Master the most popular testing framework for Java, through the Learn JUnit course:

>> LEARN JUNIT

Partner – Diagrid – NPI (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Overview

When testing, we often need access to a temporary file. However, managing, creating and deleting these files ourselves can be cumbersome.

In this quick tutorial, we’ll look at how JUnit 5 alleviates this by providing the TempDirectory extension.

For an in-depth guide to testing with JUnit, check out our excellent Guide to JUnit 5.

2. The TempDirectory Extension

Starting with version 5.4.2, JUnit 5 provides the TempDirectory Extension. However, it’s important to note that this is still an experimental feature and that we’re encouraged to give feedback to the JUnit team.

As we’ll see later, this extension can create and clean up a temporary directory for an individual test or all tests in a test class.

Usually, when using an extension, we need to register it from within a JUnit 5 test using the @ExtendWith annotation. But this is unnecessary with the TempDirectory extension, which is built-in and registered by default.

3. Maven Dependencies

First, let’s add the project dependencies we will need for our examples.

Apart from the main JUnit 5 library junit-jupiter-engine, we’ll also need the junit-jupiter-api library:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.11.0-M2</version>
    <scope>test</scope>
</dependency>

As always, we can get the latest version from Maven Central.

In addition to this, we’ll also need to add the junit-jupiter-params dependency:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.11.0-M2</version>
    <scope>test</scope>
</dependency>

Again, we can find the latest version in Maven Central.

4. Using the @TempDir Annotation

To use the TempDirectory extension, we need to use the @TempDir annotation. We can only use this annotation with the following two types:

  • java.nio.file.Path
  • java.io.File

If we try to use it with a different type, then an org.junit.jupiter.api.extension.ParameterResolutionException will be thrown.

Next, let’s explore several different ways of using this annotation.

4.1. @TempDir as a Method Parameter

Let’s begin by seeing how to inject a parameter annotated with @TempDir into a single test method:

@Test
void givenTestMethodWithTempDirectory_whenWriteToFile_thenContentIsCorrect(@TempDir Path tempDir) 
  throws IOException {
    Path numbers = tempDir.resolve("numbers.txt");

    List<String> lines = Arrays.asList("1", "2", "3");
    Files.write(numbers, lines);

    assertAll(
      () -> assertTrue("File should exist", Files.exists(numbers)),
      () -> assertLinesMatch(lines, Files.readAllLines(numbers)));
}

As we can see, our test method creates and writes a file called numbers.txt in the temporary directory tempDir.

We then check that the file exists and the content matches what was originally written. Nice and simple!

4.2. @TempDir on an Instance Field

In the following example, we’ll annotate a field in our test class using the @TempDir annotation:

@TempDir
File anotherTempDir;

@Test
void givenFieldWithTempDirectoryFile_whenWriteToFile_thenContentIsCorrect() throws IOException {
    assertTrue("Should be a directory ", this.anotherTempDir.isDirectory());

    File letters = new File(anotherTempDir, "letters.txt");
    List<String> lines = Arrays.asList("x", "y", "z");

    Files.write(letters.toPath(), lines);

    assertAll(
      () -> assertTrue("File should exist", Files.exists(letters.toPath())),
      () -> assertLinesMatch(lines, Files.readAllLines(letters.toPath())));
}

This time, we use a java.io.File for our temporary directory. Again, we write some lines and check they were written successfully.

If we were to use this single reference again in other test methods, each test would use its temporary directory.

4.3. A Shared Temporary Directory

Sometimes, we might want to share a temporary directory between test methods.

We can do this by declaring our field static:

@TempDir
static Path sharedTempDir;

@Test
@Order(1)
void givenFieldWithSharedTempDirectoryPath_whenWriteToFile_thenContentIsCorrect() throws IOException {
    Path numbers = sharedTempDir.resolve("numbers.txt");

    List<String> lines = Arrays.asList("1", "2", "3");
    Files.write(numbers, lines);

    assertAll(
        () -> assertTrue("File should exist", Files.exists(numbers)),
        () -> assertLinesMatch(lines, Files.readAllLines(numbers)));
}

@Test
@Order(2)
void givenAlreadyWrittenToSharedFile_whenCheckContents_thenContentIsCorrect() throws IOException {
    Path numbers = sharedTempDir.resolve("numbers.txt");

    assertLinesMatch(Arrays.asList("1", "2", "3"), Files.readAllLines(numbers));
  }

The key point is that we use a static field, sharedTempDir, which we share between the two test methods.

In the first test, we again wrote some lines to a file called numbers.txt. Then, in the next test, we checked that the file and its content exist.

We also enforce the order of the tests via the @Order annotation to ensure the behavior is always consistent.

4.4. The cleanup Option

Usually, the temporary directory created by @TempDir will be automatically deleted after the test execution. However, in some cases, we may want to preserve the temporary directory for debugging purposes.

For example, if a test fails, we may want to examine the contents of the temporary directory to see if there are any clues about the cause of the failure. In such cases, Junit5’s automatic deletion of the temporary directory may not be desirable.

To address this issue, Junit5 provides a cleanup option for the @TempDir annotation. The cleanup option can specify whether the temporary directory should be deleted automatically at the end of the test method.

The cleanup option can be set to one of the following CleanupMode values:

  • ALWAYS – This option specifies that the temporary directory should always be deleted automatically at the end of the test method, regardless of whether the test succeeds or fails. This is the default mode.
  • ON_SUCCESS – The temporary directory will be deleted after the test method execution only if the test succeeds.
  • NEVER – The temporary directory won’t be deleted automatically after executing the test method.

Next, let’s create a test class to verify if we set NEVER as the cleanup option’s value, the temporary directory won’t be removed after the test execution:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TemporaryDirectoryWithCleanupUnitTest {

    private Path theTempDirToBeChecked = null;

    @Test
    @Order(1)
    void whenTestMethodWithTempDirNeverCleanup_thenSetInstanceVariable(@TempDir(cleanup = NEVER) Path tempDir) {
        theTempDirToBeChecked = tempDir;
        System.out.println(tempDir.toFile().getAbsolutePath());
    }

    @Test
    @Order(2)
    void whenTestMethodWithTempDirNeverCleanup_thenTempDirShouldNotBeRemoved() {
        assertNotNull(theTempDirToBeChecked);
        assertTrue(theTempDirToBeChecked.toFile().isDirectory());
    }

}

As the class above shows, we added the @TestInstance(TestInstance.Lifecycle.PER_CLASS) annotation to the test class so that JUnit creates only one instance of the test class and uses it for all tests. This is because we’ll set the theTempDirToBeChecked instance variable in the first test and verify if the temporary directory is still there in the second test.

If we run the test, it passes. So, it indicates during the second test’s run, the temporary directory created in the first test isn’t removed.

Further, we can see the output from the first test:

/tmp/junit16624071649911791120

The INFO log from Junit5 reminds us that the temporary directory won’t be removed after the first test:

INFO: Skipping cleanup of temp dir /tmp/junit16624071649911791120 due to cleanup mode configuration.

After all test executions, if we check the temporary directory on the filesystem, the directory still exists:

$ ls -ld /tmp/junit16624071649911791120
drwx------ 2 kent kent 40 Apr  1 18:23 /tmp/junit16624071649911791120/

5. Gotchas

Let’s review some subtleties we should know when working with the TempDirectory extension.

5.1. Creation

The curious reader will probably wonder where these temporary files are created?

Well, internally, the JUnit TemporaryDirectory class makes use of the Files.createTempDirectory(String prefix) method. Likewise, this method then uses the default system temporary file directory.

This is usually specified in the environment variable TMPDIR:

TMPDIR=/var/folders/3b/rp7016xn6fz9g0yf5_nj71m00000gn/T/

For instance, resulting in a temporary file location:

/var/folders/3b/rp7016xn6fz9g0yf5_nj71m00000gn/T/junit5416670701666180307/numbers.txt

Meanwhile, if the temporary directory cannot be created, an ExtensionConfigurationException will be thrown as appropriate. Or, as previously mentioned, a ParameterResolutionException.

5.2. Deletion

The cleanup attribute’s default value is ALWAYS. That is to say, when the test method or class has finished execution and the temporary directory goes out of scope, the JUnit framework will attempt to delete all files and directories in that directory recursively and, finally, the temporary directory itself.

If there’s a problem during this deletion phase, an IOException will be thrown, and the test or test class will fail.

6. Customizing Temporary Directories Creation Using TempDirFactory

To customize the creation of temporary directories, we need to implement the TempDirFactory interface. This interface is in the org.junit.jupiter.api.io package and is part of the JUnit Jupiter API module. It’s also used with the @TempDir annotation to specify a temporary directory for a test method or class.

Also, the TempDirFactory interface has a single method called createTempDir(), which creates the temporary directory. We must implement this method with your logic when creating the temporary directory. Here’s an example implementation of the TempDirFactory interface:

class TempDirFactoryUnitTest {

    @Test
    void factoryTest(@TempDir(factory = Factory.class) Path tempDir) {
        assertTrue(tempDir.getFileName().toString().startsWith("factoryTest"));
    }

    static class Factory implements TempDirFactory {

        @Override
        public Path createTempDirectory(AnnotatedElementContext elementContext, ExtensionContext extensionContext)
                throws IOException {
            return Files.createTempDirectory(extensionContext.getRequiredTestMethod().getName());
        }

    }
}

In this example, the createTempDir() method creates a temporary directory using the Files.createTempDirectory() method from the Java NIO package. We can customize this method according to our requirements.

7. Conclusion

In this article, we’ve explored the TempDirectory Extension provided by JUnit 5.

First, we introduced the extension and learned what Maven dependencies we need to use it. Next, we looked at several examples of how to use the extension from within our unit tests.

Finally, we looked at several gotchas, including where the temporary files are created and what happens during deletion.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)