In rare cases you may want to register certain extension for each test in your test suite. A typical use case that comes to my mind is benchmarking or tracing (look JUnit OpenTelemetry Extension).
A simple but tedious approach is to decorate each test class with @ExtendWith(...)
. I don't think anyone would have such task especially in a project with large number of test classes. Fortunately, there is a better, less invasive way.
For the sake of example let's create an extension that will measure the time it takes to execute a test:
INFO
For the sake of simplicity I am using StopWatch
class from Spring Framework to measure execution time.
package com.example.junit;
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.springframework.util.StopWatch;
public class BenchmarkExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
@Override
public void beforeTestExecution(ExtensionContext context) {
var stopWatch = new StopWatch();
context.getStore(Namespace.create(BenchmarkExtension.class, context.getRequiredTestMethod()))
.put("stopWatch", stopWatch);
stopWatch.start();
}
@Override
public void afterTestExecution(ExtensionContext context) {
var testMethod = context.getRequiredTestMethod();
var stopWatch = context.getStore(Namespace.create(BenchmarkExtension.class, testMethod))
.get("stopWatch", StopWatch.class);
stopWatch.stop();
context.publishReportEntry(
String.format("Method %s#%s executed in %d ms", context.getRequiredTestClass().getName(), testMethod.getName(),
stopWatch.getLastTaskTimeMillis()));
}
}
Instead of using @ExtendWith
, we will use JUnit Service Loader capabilities to register extension and then enable extension auto-detection:
- Create a file
src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension
with content:
com.example.junit.BenchmarkExtension
- Enable extensions auto-detection in
src/test/resources/junit-platform.properties
:
junit.jupiter.extensions.autodetection.enabled=true
Note, that this enables auto-detection for all extensions registered with service loader in your classpath.
Now, when we run tests, at the end of each test following a statement similar to this one will be printed to the console:
timestamp = 2022-07-26T18:39:56.899219, value = Method com.example.MyService#testSlowMethod executed in 137 ms
While it is good to know that such feature exists, please do not abuse it - it is good to know which extensions are loaded just by looking at the test class.