Skip to content

@ContextCustomizerFactories without dirtying the context #33173

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
jamesbradlee opened this issue Jul 9, 2024 · 4 comments
Closed

@ContextCustomizerFactories without dirtying the context #33173

jamesbradlee opened this issue Jul 9, 2024 · 4 comments
Labels
in: test Issues in the test module status: invalid An issue that we don't feel is valid

Comments

@jamesbradlee
Copy link

jamesbradlee commented Jul 9, 2024

We have a need to add configuration into the spring-context at a very early stage in our tests. We have tried several solutions:

  1. @TestExecutionListeners, our problem with this is that the application is already started by the time the earliest hook in the TestExecutionListener is called. This is a problem because we need to produce system properties in the context which will be used by @ConfigurationProperties data classes. And because the app is already started, the properties won't be populated in time.

  2. ApplicationContextInitializer interface. This almost works. Except that the beans isn't loaded in time, even with @Import annotations by the consumer of the module. The solution is to do a component scan and inject the bean definitions ourselves, but because we don't know at this point which test class is being executed, and the @SpringBootApplication-annotated class isn't loaded in the bean factory by this point, there's no way to know which packages we need to scan.

  3. @ContextCustomizerFactories and ContextCustomizerFactory interface. This worked great, we were able to find our @AutoConfigureWireMock annotated test class (with superclasses) and do the component scan manually and inject the bean definitions. There are some pitfalls, like @Autowired not working like expected. But we were able to solve that. Now our problem is that one application instance is started per test class becauase the context becomes dirty, which is a problem.

So ultimately we need a solution that has some relation to which test class is being executed (while still being a part of the Spring ecosystem, so JUnit extensions won't really work like we want). And the hook must execute early enough so we can populate system properties early enough for them to be injected into constructors. And one of our most important requirements is that the context remains 'clean', so that multiple application instances isn't started for our tests. We still want our test classes to share a single application instance. edit: one thing I didn't mention here earlier is that we also need the ability to inject beans and system properties, but also retrieve get and initialize beans, so that for example the consumer of our module can create @TestConfiguration annotated WireMock configuration customizer classes, and our configuration can either do the classpath scanning ourselves and inject the bean, or we can get it from the spring-context.

Is there any part of the documentation I have overlooked, are there any other options, events and hooks that we can hook into? Is there something we can configure to prevent the ContextCustomizerFactory from dirtying the context?

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 9, 2024
@snicoll snicoll added the in: test Issues in the test module label Jul 9, 2024
@jamesbradlee
Copy link
Author

I'd be happy to create a pull request to resolve this issue - but I'm not entirely sure how you (Spring team) would like to solve this, or exactly where to begin. So a little pointer would be helpful. Thanks :)

@sbrannen sbrannen self-assigned this Jul 9, 2024
@simonbasle
Copy link
Contributor

just chiming in to ask if you've considered the equals and hashcode methods of your ContextCustomizer? This is an usual suspect in cases where too many test contexts are created. You can have a look at how the test bean override feature introduced in 6.2.0-M4 is implemented, perhaps this will provide some inspiration?

@jamesbradlee
Copy link
Author

jamesbradlee commented Jul 10, 2024

I had not thought of that! I'm returning essentially just a lambda. I'll try to implement this in a Kotlin object instead and see if the result is any different. Thanks @simonbasle

@jamesbradlee
Copy link
Author

I can finally confirm that did the trick! Thank you! I have been trying different solutions for a week now, and now I feel incredibly stupid for not reading the first two paragraphs of the java doc on the ContextCustomizer interface!

@bclozel bclozel closed this as not planned Won't fix, can't repro, duplicate, stale Jul 11, 2024
@bclozel bclozel added status: invalid An issue that we don't feel is valid and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jul 11, 2024
@sbrannen sbrannen removed their assignment Jul 12, 2024
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 status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

6 participants