The TestInstancePostProcessor defines the API for Extensions that wish to post-process test instances. This is the primary hook used for dependency injection into test instances, allowing extensions to set fields or invoke initialization methods after JUnit has created the test object.
Java source and doc
Definition of TestInstancePostProcessorVersion: 6.0.1 package org.junit.jupiter.api.extension;
@FunctionalInterface
@API(status = STABLE, since = "5.0")
public interface TestInstancePostProcessor extends TestInstantiationAwareExtension {
void postProcessTestInstance(Object testInstance, 1
ExtensionContext context)
throws Exception;
}
Example
In this example, we create a custom extension that scans the test instance for fields of type MyService. When found, the extension uses reflection to inject a concrete implementation, simulating how DI containers operate.
A service to be injected
package com.logicbig.example;
public class MyService {
private final String config;
public MyService(String config) {
this.config = config;
}
public String serve() {
return "Service active with: " + config;
}
}
Implementing TestInstancePostProcessor
package com.logicbig.example;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
import java.lang.reflect.Field;
public class ServiceInjectorExtension implements TestInstancePostProcessor {
@Override
public void postProcessTestInstance(Object testInstance,
ExtensionContext context) throws Exception {
for (Field field : testInstance.getClass().getDeclaredFields()) {
if (field.getType() == MyService.class) {
field.setAccessible(true);
field.set(testInstance, new MyService("Auto-Injected Config"));
}
}
}
}
Test Class
package com.logicbig.example;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(ServiceInjectorExtension.class)
public class PostProcessorTest {
private MyService myService;
@Test
void testInjection() {
String result = myService.serve();
System.out.println("Injection result: " + result);
}
}
Output$ mvn test -Dtest=PostProcessorTest [INFO] Scanning for projects... [INFO] [INFO] -----< com.logicbig.example:junit-5-test-instance-post-processor >------ [INFO] Building junit-5-test-instance-post-processor 1.0-SNAPSHOT [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- resources:3.3.1:resources (default-resources) @ junit-5-test-instance-post-processor --- [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-extensions\junit-5-test-instance-post-processor\src\main\resources [INFO] [INFO] --- compiler:3.13.0:compile (default-compile) @ junit-5-test-instance-post-processor --- [INFO] No sources to compile [INFO] [INFO] --- resources:3.3.1:testResources (default-testResources) @ junit-5-test-instance-post-processor --- [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-extensions\junit-5-test-instance-post-processor\src\test\resources [INFO] [INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ junit-5-test-instance-post-processor --- [INFO] Recompiling the module because of changed source code. [WARNING] File encoding has not been set, using platform encoding windows-1252, i.e. build is platform dependent! [INFO] Compiling 3 source files with javac [debug target 17] to target\test-classes [INFO] [INFO] --- surefire:3.5.0:test (default-test) @ junit-5-test-instance-post-processor --- [INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- Injection result: Service active with: Auto-Injected Config [INFO] +--com.logicbig.example.PostProcessorTest - 0.116 ss [INFO] | '-- [OK] testInjection - 0.075 ss [INFO] [INFO] Results: [INFO] [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 3.980 s [INFO] Finished at: 2025-12-31T14:55:52+08:00 [INFO] ------------------------------------------------------------------------
The execution output demonstrates that the service field was successfully populated despite never being manually initialized in the test class. By using the TestInstancePostProcessor, we were able to intercept the lifecycle after instantiation and inject the required dependency. This approach keeps test code focused on assertions rather than infrastructure and setup logic.
Example ProjectDependencies and Technologies Used: - junit-jupiter-engine 6.0.1 (Module "junit-jupiter-engine" of JUnit)
Version Compatibility: 5.0.0 - 6.0.1 Version compatibilities of junit-jupiter-engine with this example:
- 5.0.0
- 5.0.1
- 5.0.2
- 5.0.3
- 5.1.0
- 5.1.1
- 5.2.0
- 5.3.0
- 5.3.1
- 5.3.2
- 5.4.0
- 5.4.1
- 5.4.2
- 5.5.0
- 5.5.1
- 5.5.2
- 5.6.0
- 5.6.1
- 5.6.2
- 5.6.3
- 5.7.0
- 5.7.1
- 5.7.2
- 5.8.0
- 5.8.1
- 5.8.2
- 5.9.0
- 5.9.1
- 5.9.2
- 5.9.3
- 5.10.0
- 5.10.1
- 5.10.2
- 5.10.3
- 5.10.4
- 5.10.5
- 5.11.0
- 5.11.1
- 5.11.2
- 5.11.3
- 5.11.4
- 5.12.0
- 5.12.1
- 5.12.2
- 5.13.0
- 5.13.1
- 5.13.2
- 5.13.3
- 5.13.4
- 5.14.0
- 5.14.1
- 6.0.0
- 6.0.1
Versions in green have been tested.
- JDK 25
- Maven 3.9.11
|