Custom extensions let you add your own rules or actions to JUnit tests. This helps you run extra code before, after, or around tests easily.
0
0
Custom extensions in JUnit
Introduction
You want to run setup or cleanup code that applies to many tests.
You need to change how tests behave, like retrying failed tests automatically.
You want to add logging or timing around tests without changing each test method.
You want to inject dependencies or test data into your tests.
You want to check conditions before running tests and skip them if needed.
Syntax
JUnit
public class MyExtension implements BeforeEachCallback, AfterEachCallback {
@Override
public void beforeEach(ExtensionContext context) throws Exception {
// code to run before each test
}
@Override
public void afterEach(ExtensionContext context) throws Exception {
// code to run after each test
}
}Implement interfaces like BeforeEachCallback or AfterEachCallback to hook into test lifecycle.
Use ExtensionContext to get info about the test or store data.
Examples
This extension measures and prints how long each test takes.
JUnit
public class TimingExtension implements BeforeEachCallback, AfterEachCallback { private long startTime; @Override public void beforeEach(ExtensionContext context) { startTime = System.currentTimeMillis(); } @Override public void afterEach(ExtensionContext context) { long duration = System.currentTimeMillis() - startTime; System.out.println("Test took " + duration + " ms"); } }
Use
@ExtendWith to apply your custom extension to a test class.JUnit
@ExtendWith(TimingExtension.class) public class MyTests { @Test void testExample() { // test code } }
This extension retries a test up to 3 times if it fails.
JUnit
public class RetryExtension implements TestExecutionExceptionHandler { private int maxRetries = 3; @Override public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable { int attempt = 0; while (attempt < maxRetries) { attempt++; System.out.println("Retry " + attempt + " for test " + context.getDisplayName()); try { context.getRequiredTestMethod().invoke(context.getRequiredTestInstance()); return; } catch (Throwable ignored) { // continue to next retry } } throw throwable; } }
Sample Program
This test class uses the TimingExtension to print how long each test takes. The extension runs code before and after each test automatically.
JUnit
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.*; public class TimingExtension implements BeforeEachCallback, AfterEachCallback { private long startTime; @Override public void beforeEach(ExtensionContext context) { startTime = System.currentTimeMillis(); } @Override public void afterEach(ExtensionContext context) { long duration = System.currentTimeMillis() - startTime; System.out.println("Test took " + duration + " ms"); } } @ExtendWith(TimingExtension.class) public class SampleTest { @Test void fastTest() throws InterruptedException { Thread.sleep(50); } @Test void slowTest() throws InterruptedException { Thread.sleep(150); } }
OutputSuccess
Important Notes
Always keep extension code simple and fast to avoid slowing tests.
Use ExtensionContext to share data between callbacks.
Register extensions with @ExtendWith or programmatically in test suites.
Summary
Custom extensions let you add reusable code around tests.
Implement JUnit extension interfaces to hook into test lifecycle.
Apply extensions with @ExtendWith to run extra code automatically.