# The Extension Model, @TempDir and @Timeout — JUnit 5 & Mockito

Source: https://www.skillbyai.com/en/java-testing/a-extensions

> Use built-in extensions and understand how @ExtendWith works.

## Plugging behaviour into tests

JUnit Jupiter replaces JUnit 4's runners and rules with a single **extension model**. An **extension** can hook into lifecycle callbacks (before and after each test), resolve **parameters** for test methods and constructors, handle exceptions, decide whether tests run, and more. Register extensions with **`@ExtendWith(SomeExtension.class)`**, programmatically with `@RegisterExtension` on a field, or automatically via service loading. Popular extensions: **`MockitoExtension`** (initialises `@Mock` fields and enforces strict stubbing), **`SpringExtension`** (used by Spring Boot test annotations), Testcontainers' `@Testcontainers`, and many in libraries. JUnit also ships useful built-in features. **`@TempDir`** injects a fresh temporary directory that is deleted after the test, perfect for file-handling code. **`@Timeout(2)`** fails a test (or every test in a class) that runs longer than the limit. Parameter resolution also injects **`TestInfo`** (the current test's name and tags) and **`TestReporter`** for publishing extra information.

## Extensions around a test

Extensions hook in before and after each test and can supply parameters.

![A central test box surrounded by small plug-in shapes attached on all sides.](assets/figures/java-testing/section-3-map.svg) — Figure 3.1 — Extensions hooking into the test lifecycle.

## Temporary directories, timeouts and a custom extension

A tiny extension that measures each test's duration.

```java
class ReportWriterTest {

    @Test
    @Timeout(2)                               // seconds
    void writesCsvReport(@TempDir Path dir) throws IOException {
        Path file = dir.resolve("sales.csv");
        new ReportWriter().write(file, List.of(new Sale("pen", 2)));

        assertThat(Files.readAllLines(file)).containsExactly("sku,qty", "pen,2");
    }   // dir and its contents are deleted automatically
}

public class TimingExtension implements BeforeEachCallback, AfterEachCallback {
    private static final ExtensionContext.Namespace NS = ExtensionContext.Namespace.create(TimingExtension.class);

    @Override public void beforeEach(ExtensionContext ctx) {
        ctx.getStore(NS).put("start", System.nanoTime());
    }
    @Override public void afterEach(ExtensionContext ctx) {
        long start = ctx.getStore(NS).remove("start", Long.class);
        long ms = (System.nanoTime() - start) / 1_000_000;
        ctx.publishReportEntry("durationMs", String.valueOf(ms));
    }
}

@ExtendWith(TimingExtension.class)
class SlowServiceTest { /* tests report their duration */ }
```

## Prefer @TempDir to hard-coded paths

Tests that write to `/tmp/report.csv` collide when run in parallel and leave files behind. `@TempDir` gives each test its own directory and cleans up afterwards.

**Quiz:** What replaced JUnit 4 runners and rules in JUnit Jupiter?

- [x] The extension model with @ExtendWith
- [ ] XML configuration
- [ ] Abstract base test classes only
- [ ] System properties

*Answer:* The extension model with @ExtendWith. Jupiter has a single, composable extension model registered with @ExtendWith and related mechanisms.
