It seems like a fairly minor complaint on the surface, but I think it goes fairly deep. The issue manifests as a difference between using @EnableAutoConfiguration and @ImportAutoConfiguration, which mostly we haven't really cared much about because we kind of expect everyone to use @EnableAutoConfiguration (via @SpringBootApplication). But there is now quite a bit of evidence that @ImportAutoConfiguration is a useful tool in its own right, so we should expect that it works the same way.

You can recreate the issue pretty easily with this app:

@SpringBootConfiguration
@ComponentScan
@EnableAutoConfiguration
public class SampleApplication {

    @Bean
    public CommandLineRunner runner(JdbcTemplate jdbc) {
        return args -> {
            jdbc.update("INSERT into foo (id, value) VALUES (1, 'Hello')");
        };
    }

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }

    @Configuration
    @EntityScan
    @AutoConfigurationPackage
    protected static class Packages {
    }

}

@RestController
class SampleController {

    private FooRepository foos;

    public SampleController(FooRepository foos) {
        this.foos = foos;
    }

    @GetMapping("/")
    String home() {
        return foos.findById(1L).get().getValue();
    }

}

interface FooRepository extends JpaRepository<Foo, Long> {
}

@Entity
class Foo {

    @Id
    @GeneratedValue
    private Long id;
    private String value;

    public Foo() {
    }

    public Foo(String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Foo [value=" + this.value + "]";
    }

}

The app runs fine but if you try to write an test like this:

@RunWith(SpringRunner.class)
@WebMvcTest(SampleController.class)
public class WebMvcApplicationTests {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void test() throws Exception {
        mockMvc.perform(get("/")).andExpect(status().isOk())
                .andExpect(content().string("Hello"));
    }

}

it fails. And it should, because there is no implementation of FooRepository. The problem is if you replace @EnableAutoConfiguration with explicit configurations:

@SpringBootConfiguration
@ComponentScan
@ImportAutoConfiguration({ PropertyPlaceholderAutoConfiguration.class,
ConfigurationPropertiesAutoConfiguration.class, DataSourceAutoConfiguration.class,
JdbcTemplateAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
ServletWebServerFactoryAutoConfiguration.class, WebMvcAutoConfiguration.class,
ErrorMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class })
public class SampleApplication {
...
}

then the app still runs but the test does not fail, because all of the @ImportAutoConfiguration classes are actually imported as part of the test configuration, when they should be excluded.

The problem probably comes down to this code in AutoConfigurationImportSelector:

    protected boolean isEnabled(AnnotationMetadata metadata) {
        if (getClass() == AutoConfigurationoImportSelector.class) {
            return getEnvironment().getProperty(
                    EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
                    true);
        }
        return true;
    }

which relies on @EnableAutoConfiguration and @ImportAutoConfiguration having different ImportSelector implementations.

Comment From: snicoll

Your original setup is broken in any case. If you don't use @SpringBootApplication you are not relying on the extra AutoConfigurationExcludeFilter that it configures. If you're not using it, then the component scan tuning that test slices apply will not work properly. There is a note in the documentation.

What you are describing as an issue is also referenced in the documentation. Whatever "import directives" that you add in your root bootstrap context class will be applied. The example in the doc mentions @EnableBatchProcessing but it is a general note.

Having said all of that, I am not sure what you are reporting here, really. If you are explicitly importing auto-configurations in the class that is the source of your test, I don't really understand how you expect us to ignore that. What if the user wants slicing and a couple of extra auto-configurations? Should we prevent that as well?

Comment From: dsyer

I agree that Spring Boot is probably working as designed. I want to change the design I guess. I need a way to write an app using autoconfiguration, not using @EnableAutoConfiguration, but keeping all the benefits. I don't really mind how that gets implemented. It can be a new annotation or something. We can change the issue summary to reflect whatever works for you. The sample above is just a concrete example of how it should work and currently doesn't.

Comment From: philwebb

For now you might be able to subclass AutoConfigurationImportSelector and override isEnabled and getCandidateConfigurations.

Comment From: dsyer

Yeah, that should work. I'll see what I can come up with.

Comment From: philwebb

I'd like to park this until we've had some time to look at #15738 since it could change the landscape considerably.

Comment From: wilkinsona

We’re cleaning out the issue tracker and closing issues that we’ve not seen much demand to fix. Feel free to comment with additional justifications if you feel that this one should not have been closed.