-
Notifications
You must be signed in to change notification settings - Fork 41.1k
Provide annotation based-configuration for hierarchical applications/contexts #24583
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
Comments
Isn' that what the //cc @sbrannen |
With |
This sounds like it might be related to #22405 in terms of reusing programmatic configuration in tests.
You can build hierarchies with siblings as long as the siblings are configured in different test classes. @ContextHierarchy(@ContextConfiguration(classes = BaseConfig.class))
class BaseTests {}
@ContextConfiguration(classes = Child1Config.class)
class Child1Tests extends BaseTests {}
@ContextConfiguration(classes = Child2Config.class)
class Child2Tests extends BaseTests {} The application contexts for the two subclasses are siblings since they have the same parent application context. The above results in 3 distinct application contexts in the context cache.
That's correct, but #22405 may help to alleviate that (unless I've misunderstood the goals of that issue).
Are you saying you want to be able to have beans from sibling application contexts injected into the same test class instance? If so, please expound on the use case and rationale for wanting that. In any case, to the best of my knowledge there is no support in the Spring Framework or Spring Boot for performing dependency injection from multiple (sibling) application contexts. For example, the whole In other words, I don't think what you're asking for is currently possible, and to make it possible would likely require considerable effort that is not warranted by the benefit. |
I agree, but having a context hierarchy seems to be a bit more advanced than the use cases discussed in #22405. Nevertheless the limitation is similar.
Let me try to explain the motivation: As mentioned in my initial post we use hierarchical Spring applications for building modular monoliths. Each module is represented by a child context. Therefore we do not have deep hierarchies. There is just a root context and several direct children of that root context. Modules cannot access beans of other modules, but there are certain beans (like an EventBus) which can be used for inter-module communication. Imagine this EventBus is a bean of the parent context and all the child contexts can use this EventBus to subscribe to events and to publish events. A scenario I'd like to test:
Of course all of this can be tested in isolation using mocks, but I would like to have the possibility to test it in an integrated (end-to-end) manner. Currently I write the test similar to this: @Configuration
static class TestConfig {
@Bean
ChildEventHandler childEventHandler( ) {
return mock( ChildEventHandler.class );
}
}
static class ChildEventHandler {
@EventHandler
void on( final MyEvent myEvent) {
}
}
static class MyEvent {
}
@Test
void test() {
// Initialization
final String[] args = new String[] { };
final SpringApplication parentApplication = new SpringApplication( ParentConfig.class );
final ConfigurableApplicationContext parentContext = parentApplication.run( args );
final SpringApplication child1Application = new SpringApplication( TestConfig.class, Child1Config.class );
final SpringApplication child2Application = new SpringApplication( TestConfig.class, Child2Config.class );
child1Application.addInitializers( new ParentContextApplicationContextInitializer( parentContext ) );
child2Application.addInitializers( new ParentContextApplicationContextInitializer( parentContext ) );
final ConfigurableApplicationContext child1Context = child1Application.run( args );
final ConfigurableApplicationContext child2Context = child2Application.run( args );
// Test
final ChildEventHandler child1EventHandler = child1Context.getBean( ChildEventHandler.class );
final EventBus child2EventBus = child2Context.getBean( EventBus .class );
final MyEvent myEvent= new MyEvent ( );
child2EventBus .publish( myEvent);
verify( child1EventHandler, timeout( 3000 ) ).on( myEvent);
// Shutdown
child1Context.close( );
child2Context.close( );
parentContext.close( );
} What happens behind the scenes:
That's the reason why I use Mockito's I hope I could clarify why and how we use hierarchical contexts. If you have any further questions feel free to ask. |
I decided to put this issue into a working example: https://github.com/OLibutzki/spring-boot-24583 The interesting part is SpringBoot24583Test. As you can see there is a lot manual In my opinion the referenced repository might be a good starting point for improving the support. |
Adding additional attributes to I think the real problem discussed in this issue is that it's hard to use I'm going to mark this one as duplicate of #22405 since I think that's the better issue for us to focus on. |
Spring Boot offers support for hierarchical application contexts by using
org.springframework.boot.builder.SpringApplicationBuilder
.We use it quite a lot to build Spring based modular monoliths as it's a powerful tool to encapsulate the modules within the same Java process.
org.springframework.boot.builder.SpringApplicationBuilder
works flawlessly, but this approach has its limitations when it comes to integration testing.Imaginge you have two children which are siblings. As far as I know it's not (easily) possible to setup this scenario in an integration test. I would like to use all the great support of
@SpringBootTest
.Having a annoation-based API to configure context hierarchies might be a good starting point for testing such a hierarchical application.
Not sure if this should be provided by
@SpringBootApplication
or a dedicated annoation, but first of all I just want to explain the ideaIn the integration Test I would like to use (and mock) beans of both contexts:
I know that this idea needs some fine-tuning, but I just would like to share it with you in order to get to know if it's worth to think about it any further.
Edit: If you are aware of a way how to test this setup appropriately it would be fine as well.
//cc @sbrannen
The text was updated successfully, but these errors were encountered: