पाठ 7 / 25

The Extension Model, @TempDir and @Timeout

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.
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.

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.

त्वरित जाँच: What replaced JUnit 4 runners and rules in JUnit Jupiter?

  • 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.