JUnit Jupiter's @TempDir annotation accepts a cleanup attribute with the values ALWAYS, ON_SUCCESS and NEVER. What does each do, which is the default, and why would you change it?
answer
- ALWAYS = default
- ON_SUCCESS = keep evidence on failure
- NEVER = leaks disk, debugging only
- junit.jupiter.tempdir.cleanup.mode.default
- annotation value beats global default
basics
~20 sALWAYS (the default) deletes the directory when its scope ends whatever the outcome. ON_SUCCESS deletes it only if the test passed, keeping the files for inspection when it failed. NEVER always keeps it. You can also set the default globally with the junit.jupiter.tempdir.cleanup.mode.default configuration parameter.
solid answer
~50 s`@TempDir(cleanup = ...)` controls whether Jupiter deletes the directory when its scope ends. - **ALWAYS** — the default; delete regardless of the test outcome. - **ON_SUCCESS** — delete only when the test passed; on failure the directory and its contents survive so you can inspect what the code actually wrote. - **NEVER** — never delete; the OS temp cleaner is your only garbage collector. The usual reason to change it is debugging a filesystem test: `ON_SUCCESS` turns a "the assertion says the file is wrong" failure into an artefact you can open. It is the safest non-default because the directory only lingers when something is already broken. `NEVER` should be temporary and local; committed it leaks a directory per test on every CI run. You can also flip the default for a whole build with the configuration parameter `junit.jupiter.tempdir.cleanup.mode.default=ON_SUCCESS`, which is a reasonable local-development setting.
code
java · 16 linesimport org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.CleanupMode;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.Path;
class ExportTest {
@Test
void keepsFilesWhenItFails(
@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path dir) throws Exception {
new Exporter().writeTo(dir);
// if this assertion fails, dir survives for inspection
org.junit.jupiter.api.Assertions.assertTrue(
java.nio.file.Files.exists(dir.resolve("export.json")));
}
}go deeper
Name the three constants and that ALWAYS is the default.
Explain ON_SUCCESS as the debugging aid and mention the junit.jupiter.tempdir.cleanup.mode.default configuration parameter.
Frame it as a policy question — default ALWAYS in CI, ON_SUCCESS locally — and be clear that NEVER masks handle leaks and grows temp space unbounded.
Discuss the tradeoff between artefact retention for diagnosing rare CI failures and disk hygiene on long-lived agents, and prefer explicit artefact copying in teardown over leaving temp directories behind.
## What the attribute controls By default a `@TempDir` directory is destroyed the moment its scope ends. That is right for green runs and wrong exactly when you most want the files: after a failure. The `cleanup` attribute (`org.junit.jupiter.api.io.CleanupMode`) makes that behaviour selectable. ```java @Test void producesArchive(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path dir) { ... } ``` ### ALWAYS The default. When the scope ends — after `@AfterEach` for a method-scoped directory, after `@AfterAll` for a class-scoped one — Jupiter recursively deletes the tree. This is what keeps a suite hermetic and keeps temp space bounded on long-lived CI agents. ### ON_SUCCESS Delete only if the test completed successfully. If the test failed — an assertion failed or an exception escaped — the directory is left in place and Jupiter is silent about it beyond the path already being visible in your test's own diagnostics. You then open the directory and look at the file the code actually produced: truncated CSV, wrong encoding, missing trailing newline, a lock file nobody closed. This is dramatically faster than adding print statements and re-running. Note the semantics of "success": an *aborted* test (an assumption that did not hold, which surfaces as `TestAbortedException`) is not a failure, so the directory is cleaned up. ### NEVER Keep it unconditionally. Useful for a few minutes when you want the artefacts of a passing test — say to eyeball a generated report or feed it into another tool — and occasionally when an external process must pick the files up after the JVM exits. It is not a fix for deletion failures: if cleanup is failing because you leaked a file handle, `NEVER` hides the symptom and leaves the bug. ## Setting the default globally Rather than annotating every declaration, set the Jupiter configuration parameter: ``` junit.jupiter.tempdir.cleanup.mode.default = ON_SUCCESS ``` Jupiter reads configuration parameters from a `junit-platform.properties` file on the test classpath, from JVM system properties, or from parameters supplied by the launcher. An explicit `cleanup` value on an individual `@TempDir` always wins over the global default. A sensible policy is: leave the global default at `ALWAYS` for committed code and CI, and let individual developers set `ON_SUCCESS` locally (system property or a local properties file) while debugging. Committing `ON_SUCCESS` build-wide is defensible for a suite whose failures are hard to reproduce, provided the agents have disk headroom and something reaps `java.io.tmpdir`. ## Where the leftovers actually go Under the default factory the directory sits under `java.io.tmpdir` with a `junit`-prefixed random name. Depending on the OS that space may be cleaned only on reboot or by a periodic reaper, so on a long-running CI agent "never delete" really does mean unbounded growth, one directory per test, per run. That is the argument for keeping `NEVER` out of the repository. ## Failure to delete Separately from the mode, deletion itself can fail — most often on Windows, where an open file handle prevents removal. Jupiter reports that as a failure attached to the test with a message about being unable to delete the temp directory, and it lists the entries it could not remove. The correct response is to close the handle, not to switch the mode to `NEVER`. ## Interview framing Name the three constants and the default, then say the practical thing: `ON_SUCCESS` is the debugging setting because it keeps evidence exactly when there is a problem, `NEVER` is a foot-gun that leaks disk, and the global default can be moved with `junit.jupiter.tempdir.cleanup.mode.default` if you want it suite-wide. Mentioning that an aborted (assumption-failed) test still counts as a non-failure for `ON_SUCCESS` is a nice extra.
- With CleanupMode.ON_SUCCESS, is the directory deleted when a test is skipped because an assumption did not hold?Yes. An assumption that does not hold aborts the test with a TestAbortedException, which JUnit treats as aborted rather than failed, so the directory is cleaned up. ON_SUCCESS only preserves the directory for genuine failures — a failed assertion or an escaping exception.
- How would you switch a whole module to ON_SUCCESS without touching every annotation?Set the Jupiter configuration parameter junit.jupiter.tempdir.cleanup.mode.default=ON_SUCCESS, for example in a junit-platform.properties file on the test classpath or as a JVM system property. Any explicit cleanup value on an individual @TempDir still overrides it.
saying these in an interview costs you the question
- Believing NEVER is the right cure for an 'unable to delete temp directory' failure
- Thinking ON_SUCCESS keeps the directory for skipped or aborted tests
- Assuming the default is ON_SUCCESS rather than ALWAYS
- Committing NEVER to the repository and letting CI agents fill up
- Claiming cleanup mode can only be set per annotation, with no global configuration parameter