Search code examples
javaspring-bootdependency-injectionintegration-testing

@ConditionalOnBean not being triggered even though Bean exists in SpringBootTest


I have the following AutoConfiguration class:

@Configuration
public class MyAutoConfiguration {
  @AutoConfigureAfter(MockMvcAutoConfiguration.class)
  class MyNestedAutoConfiguration {
    @ConditionalOnBean(MockMvc.class)
    @Bean
    AugmentedMockMvc augmentedMockMvc(MockMvc mockMvc) {
      return new AugmentedMockMvc(mockMvc);
    }
  }
}

The class is properly registered in spring.factories, and it is imported as a maven dependency in my Spring Boot application. My Spring Boot application looks like the following:

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

Finally, I have an integration test that is defined like this:

@SpringBootTest(classes = {MySpringBootApp.class})
@AutoConfigureMockMvc
@ContextConfiguration(initializers = {MyInitializer.class})
class MyTest {
  @Autowired
  private AugmentedMockMvc augmentedMockMvc;
}

MyInitializer can be ignored, it doesn't do anything meaningful here, but it is needed and therefore I need to use both @SpringBootTest and @ContextConfiguration.

The issue is the following: With this setup, the augmentedMockMvc Bean is not created because it does not match the @ConditionalOnBean(MockMvc.class) condition.

I tried two things:

  • Adding classes = {MockMvcAutoConfiguration.class} to @ContextConfiguration. This works fine and fixes the issue, the augmentedMockMvc Bean is now properly registered
  • Removing the @ConditionalOnBean(MockMvc.class) annotation from the Bean creation. Weirdly enough, this also works! The MockMvc Bean is actually there, but it is not discovered by Spring when evaluating the @ConditionalOnBean annotation.

I don't understand why the MockMvc Bean is not found by the @ConditionalOnBean(MockMvc.class) even though the Bean exists unless I specifically put the class in the @ContextConfiguration, I would think that having @AutoConfigureMockMvc on MyTest should be enough for the MockMvcAutoConfiguration.class class to be in the context


Solution

  • @AutoConfigureAfter only works on a top-level class that is listed in spring.factories. You haven't shown your spring.factories file, but assuming that it lists MyAutoConfiguration, that's the class on which @AutoConfigureAfter should be placed.