Summary
Hello Spring. Forgive me if this is better transferred to Spring Framework, but I found an inconsistent behavior with AutoConfiguration ordering in a @SpringBootTest
when using @ImportAutoConfiguration
so posting it here first.
Consider the case where I have 3 AutoConfigurations where one of the AutoConfigurations wants to run before one, but after another, and one of these AutoConfiguration comes from another spring library.
The library AutoConfiguration
@AutoConfiguration
public class BarAutoConfiguration {
@Bean
public Bar bar() {
return new Bar();
}
}
And the other two AutoConfiguration
@Configuration
@AutoConfigureBefore(AppConfig.class)
@AutoConfigureAfter(name = "com.example.library.BarAutoConfiguration")
@ConditionalOnClass(Bar.class)
@ConditionalOnBean(Bar.class)
public class FooConfig {
@Bean
public Foo foo(Bar bar) {
return new Foo(bar);
}
}
@Configuration
public class AppConfig {
@Bean
public ConsumerOfFoo consumerOfFoo(List<Foo> foo) {
return new ConsumerOfFoo(foo);
}
}
I then want to have a a tests that Loads all 3 of these in this manner.
@SpringBootTest(classes = {AppConfig.class, FooConfig.class}, properties = {"debug=true"})
@ImportAutoConfiguration(BarAutoConfiguration.class)
public class FooConsumerTest {
@MockitoSpyBean
private Bar bar;
@Autowired
ConsumerOfFoo consumerOfFoo;
@Test
public void spanishTest() {
Mockito.when(bar.getGreeting()).thenReturn("Hola");
// test assertions
}
}
In this case, BarAutoConfiguration
is not ran before FooConfig
as directed by @AutoConfigureAfter(name = "com.example.library.BarAutoConfiguration")
so the conditions of the test breaks as the Foo
bean is not created early enough. The specific ordering directives do not seem to be applied as expected.
Expectations
AutoConfiguration ordering would be preserved in @SpringBootTest
for imported AutoConfigurations.
Workarounds
I can, of course, move BarAutoConfiguration
into classes {}
block and config order behaves as expected. The reason I might not want to do this is I may want to eventually create a test slice for BarAutoConfiguration
and apply that annotation in this tests so consumers of the library don't need to know the specific configuration to add. This is a pattern we've been adding to most of our libraries to allow users to create smaller and more efficient tests without understanding the code structure and using documented test slices instead.
Reproducer
I dropped a Reproducer of this example here. You can run this test to reproduce the ordering problem.
Comment From: snicoll
What is the purpose of @ImportAutoConfiguration(BarAutoConfiguration.class)
on that test?
Comment From: iparadiso
What is the purpose of
@ImportAutoConfiguration(BarAutoConfiguration.class)
on that test?
To also import it into the test as it's needed as an external auto-configuration for the minimal test.
It's really a placeholder of an custom tests slice as I mention in the workarounds
section. The goal is minimal tests that don't load the world and write custom test slice annotations so users don't need to understand the library code structure to bring those beans into a tests.