Referring to issue #26141, #26142 and most specifically #26143, these are all stemming from attempts by me to create a type of @EnableAcmeLibraryTest annotation (with optional parameters) that you could slap on a test, and then have both the Spring context and the test instance processed to have the necessary test infrastructure given straight into your hands.

From #26143, @sbrannen pointed me in the direction of ContextCustomizerFactory with its ContextCustomizer. This actually seems to fully cover the needs of the first requirement, i.e. tailoring the Spring context before it is refreshed (the other need, tailoring the test instance, would have been covered by TestExecutionListeners, had it not been for #26141). However, the mechanism is a SPI-style tool, whereby you need to register such factories in a META-INF/spring.factories file on the classpath.

IMO, this is too opaque and "too magic" for my liking. With this I mean that you cannot anymore trust that the code in front of you actually fully represent what will happen - there are also code being "wedged in" from unrelated, seemingly "magic" places.

This SPI-style also makes it harder to use this functionality as a project-specific tool, i.e. "just for these 87 tests in this specific project", due to this being a different and unfamiliar style of coding outside of "pure Java + Spring", introducing opaque aspect-style cross-cutting concerns where some elements are introduced without explicit reference, from a rather different part of the project file tree.

By letting a ContextCustomizer be introduced declaratively by an annotation (possibly specifying the ContextCustomizerFactory to instantiate?), you would immediately fix this: As a user of the AcmeLibrary, to get the functionality you desire, you will have to explicitly annotate the test class with a AcmeLibrary-specific annotation making the use obvious, and by only following the code, you could fully understand what happens. Also, for project-specific usages, it would just be clean Java+Spring, no SPI-style META-INF cruft to handle.

It would obviously be a massive positive if it was possible to employ this functionality as a meta-annotation in such a way that the resulting @EnableAcmeLibraryTest could take annotation parameters which could be employed by the ContextCustomizer[Factory] to programmatically tailor how the Spring context should be customized. (It should also be implemented in such a way that nothing prevents the @EnableAcmeLibraryTest to also employ a @TestExecutionListener to also tailor the test class instance.)

Comment From: sbrannen

We will investigate introducing support for declarative ContextCustomer registration in the Spring TestContext Framework, potentially for inclusion before 6.0 GA.

Introducing such support would provide a test class aware alternative to ApplicationContextInitializer.

One option would be to introduce a new @ContextCustomizers (or @ContextCustomizerFactories) type-level annotation analogous to @TestExecutionListeners.

Comment From: stolsvik

Thanks for positive feedback. Please take into account all the three issues I refer to in the OP, which point to a problem when using the annotations @ActiveProfiles, @ContextConfigration, and specifically @TestExectionListeners in "merged" (inherited) modus. The latter would be needed inside the original idea of @EnableAcmeLibraryTest - but using such annotation would then prevent, by the deficiency these annotations have, the use of them individually on the testclass itself (or would ruin the @EnableAcmeLibraryTest by not kicking in - I do not remember which one is picked up first)

Comment From: sbrannen

Current work on this feature can be viewed in the following feature branch.

https://github.com/sbrannen/spring-framework/commits/issues/gh-26148-ContextCustomizer-declarative-registration

Comment From: sbrannen

The solution in the aforementioned feature branch is effectively feature complete; however, it is based on the semantics of our @TestExecutionListeners support which does not allow @ContextCustomizerFactories to be discovered on multiple, local composed annotations. In other words, just like with @TestExecutionListeners, only the closest @ContextCustomizerFactories annotation is taken into account.

I would like to investigate honoring all local @ContextCustomizerFactories annotations and merging the lists of factories to register. In light of that, I am postponing the continuation of this work to 6.1 M4.

Comment From: sbrannen

Support for @ContextCustomizerFactories is now available on main for inclusion in the forthcoming Spring Framework 6.1 M5 release.

Please give it a try and let us know what you think!

  • See also #31204