0
0
JUnittesting~7 mins

Custom extensions in JUnit

Choose your learning style9 modes available
Introduction

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.

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.