Reputation: 165
I've been desperately trying to build an extension that requires information from both the JUnit5 extension model and the Spring-Boot Test framework. Specifically, I'd like to hook into the ApplicationContext creation process using a ApplicationContextInitializer
and a custom annotation:
@Retention(RUNTIME)
@Target(TYPE)
@ContextConfiguration(initializers = CustomContextInitializer.class)
public @interface CustomAnnotation {
String someOption();
}
The test then looks like this:
@SpringBootTest
@CustomAnnotation(someOption = "Hello There")
public class SomeTest {
...
}
Now, how do I access the CustomAnnotation
instance of the test class from within my CustomContextInitializer
?
class CustomContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// How to access the Test Class here?
CustomAnnotation annotation = <Test Class>.getAnnotation(CustomAnnotation.class);
System.out.println(annotation.someOption());
}
}
Is it possible to somehow access the JUnit5 ExtensionContext
during the creation of the ApplicationContext? It doesn't have to be from within a ApplicationContextInitializer
. I just need a hook that is executed early enough so that I can inject some dynamically generated properties before the whole bean instantiation process actually starts.
Upvotes: 1
Views: 1687
Reputation: 866
You can implement your own TestExecutionListener
and use it to access annotation you mentioned
@Retention(RUNTIME)
@Target(ElementType.TYPE)
@TestExecutionListeners(listeners = CustomTestExecutionListener.class, mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
@interface CustomAnnotation {
String someOption();
}
static class CustomTestExecutionListener implements TestExecutionListener {
@Override
public void beforeTestClass(TestContext testContext) throws Exception {
final CustomAnnotation annotation = testContext.getTestClass().getAnnotation(CustomAnnotation.class);
System.out.println(annotation.someOption());
}
}
Upvotes: 0
Reputation: 1131
Take a look at @DynamicPropertySource
for injecting properties before the bean initialization. You can then use @RegisterExtension
to register a custom extension that reads the annotation properties and makes them available through some method:
@CustomAnnotation(someOption = "Hello There")
public class SomeTest {
@RegisterExtension
static CustomExtension extension = new CustomExtension();
@DynamicPropertySource
static void registerProperties(DynamicPropertyRegistry registry) {
registry.add("property.you.need",
() -> customExtension.getProperty());
}
}
public class CustomExtension implements BeforeAllCallback {
private String property;
public String getProperty() {
return property;
}
@Override
public void beforeAll(ExtensionContext context) throws Exception {
CustomAnnotation annotation = context.getRequiredTestClass()
.getAnnotation(CustomAnnotation.class);
property = annotation.someOption();
}
}
I know it doesn’t answer the question about hooking JUnit 5 with Spring initialization mechanism, but if dynamic properties is all you need, this solves exactly that.
Upvotes: 1