Skip to content

Support declarative ContextCustomizer registration in the TestContext framework #26148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
stolsvik opened this issue Nov 24, 2020 · 5 comments
Closed
Assignees
Labels
in: test Issues in the test module type: enhancement A general enhancement
Milestone

Comments

@stolsvik
Copy link

stolsvik commented Nov 24, 2020

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.)

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Nov 24, 2020
@rstoyanchev rstoyanchev added the in: test Issues in the test module label Nov 11, 2021
@sbrannen sbrannen added the type: enhancement A general enhancement label Jun 7, 2022
@sbrannen sbrannen changed the title Test-framework: Register ContextCustomizer declaratively via an annotation Support declarative ContextCustomizer registration in the TestContext framework Jun 7, 2022
@sbrannen sbrannen removed the status: waiting-for-triage An issue we've not yet triaged or decided on label Jun 7, 2022
@sbrannen sbrannen added this to the 6.0.0-M6 milestone Jun 7, 2022
@sbrannen
Copy link
Member

sbrannen commented Jun 7, 2022

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.

@sbrannen sbrannen self-assigned this Jun 7, 2022
@stolsvik
Copy link
Author

stolsvik commented Jun 7, 2022

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)

@sbrannen sbrannen modified the milestones: 6.0.0-M6, 6.0.0-RC1 Aug 29, 2022
@sbrannen sbrannen modified the milestones: 6.0.0-RC1, 6.0.x Oct 10, 2022
@jhoeller jhoeller modified the milestones: 6.0.x, 6.1.x Mar 7, 2023
@sbrannen sbrannen modified the milestones: 6.1.x, 6.1.0-M2 Jun 19, 2023
@sbrannen
Copy link
Member

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

@sbrannen sbrannen changed the title Support declarative ContextCustomizer registration in the TestContext framework Support declarative ContextCustomizer registration in the TestContext framework Jul 6, 2023
@sbrannen
Copy link
Member

sbrannen commented Jul 11, 2023

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.

@sbrannen sbrannen modified the milestones: 6.1.0-M2, 6.1.0-M3 Jul 11, 2023
@jhoeller jhoeller modified the milestones: 6.1.0-M3, 6.1.0-M4 Jul 17, 2023
sbrannen added a commit to sbrannen/spring-framework that referenced this issue Aug 13, 2023
@sbrannen sbrannen removed this from the 6.1.0-M4 milestone Aug 16, 2023
@sbrannen sbrannen added this to the 6.1.0-RC1 milestone Aug 16, 2023
sbrannen added a commit to sbrannen/spring-framework that referenced this issue Sep 13, 2023
@sbrannen
Copy link
Member

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants