Skip to content

AutoConfiguration order is not honored in @SpringBootTest with @ImportAutoConfiguration #46836

@iparadiso

Description

@iparadiso

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.

@AutoConfiguration(before = AppConfig.class, afterName = "com.example.library.BarAutoConfiguration")
@ConditionalOnClass(Bar.class)
@ConditionalOnBean(Bar.class)
public class FooConfig {

    @Bean
    public Foo foo(Bar bar) {
        return new Foo(bar);
    }

}

@AutoConfiguration
public class AppConfig {

    @Bean
    public ConsumerOfFoo consumerOfFoo(List<Foo> foo) {
        return new ConsumerOfFoo(foo);
    }
}

To aid in testing, I also created a test slice for my library

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@ImportAutoConfiguration
public @interface EnableBarTest {

}

Which simply loads com.example.library.BarAutoConfiguration via META-INF/spring/com.example.library.EnableBarTest.imports

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"})
@EnableBarTest   // imports BarAutoConfiguration
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 afterName = "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. I don't want to do that since this comes from an external library which requires the app to understand the code. Instead I want them to simply use my @EnableBarTest test slice which uses the @ImportAutoConfiguration mechanism. This allows me to decouple and change auto-configurations in my library without breaking users.

Reproducer

I dropped a Reproducer of this example here. You can run this test to reproduce the ordering problem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: invalidAn issue that we don't feel is valid

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions