spring-bootspring-boot-test

How to test @ConfigurationProperties with ApplicationContextRunner from spring-boot-test?


I need to test my autoconfiguration classes that make use of @ConfigurationProperties beans. I'm making use of ApplicationContextRunner as documented in https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-test-autoconfig to make tests faster and avoid starting the servlet container between each variations. However, beans annotated with @AutoconfigurationProperties are not populated with values injected into ApplicationContextRunner.

I suspect that I'm hitting problem similar to https://stackoverflow.com/a/56023100/1484823

@ConfigurationProperties are not managed by the application context you build in tests, although they will be load when the application launches, because you have @EnableConfigurationProperties on your app main class.

How can I enable support for @ConfigurationProperties with ApplicationContextRunner ?

Here is the corresponding code

    @Test
    void ServiceDefinitionMapperPropertiesAreProperlyLoaded() {
        ApplicationContextRunner contextRunner = new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(
                SingleServiceDefinitionAnswerAutoConfig.class,
                DynamicCatalogServiceAutoConfiguration.class
            ))
//          .withPropertyValues(DynamicCatalogProperties.OPT_IN_PROPERTY + "=true") //Not sure why this seems ignored
            .withSystemProperties(DynamicCatalogConstants.OPT_IN_PROPERTY + "=true",
                ServiceDefinitionMapperProperties.PROPERTY_PREFIX
                +ServiceDefinitionMapperProperties.SUFFIX_PROPERTY_KEY+ "=suffix")
        ;
        contextRunner.run(context -> {
            assertThat(context).hasSingleBean(ServiceDefinitionMapperProperties.class);
            ServiceDefinitionMapperProperties serviceDefinitionMapperProperties
                = context.getBean(ServiceDefinitionMapperProperties.class);
            assertThat(serviceDefinitionMapperProperties.getSuffix()).isEqualTo("suffix");
        });
    }

which fails with:

 org.opentest4j.AssertionFailedError: 
Expecting:
 <"">
to be equal to:
 <"suffix">
but was not.
Expected :suffix
Actual   :
<Click to see difference>
    at org.springframework.cloud.appbroker.autoconfigure.DynamicCatalogServiceAutoConfigurationTest
public class DynamicCatalogServiceAutoConfiguration {

[...]

    @Bean
    @ConfigurationProperties(prefix=ServiceDefinitionMapperProperties.PROPERTY_PREFIX, ignoreUnknownFields = false)
    public ServiceDefinitionMapperProperties serviceDefinitionMapperProperties() {
        return new ServiceDefinitionMapperProperties();
    }
[...]
}

Full sources available at https://github.com/orange-cloudfoundry/osb-cmdb-spike/blob/0da641e5f2f811f48b0676a25c8cbe97895168d1/spring-cloud-app-broker-autoconfigure/src/test/java/org/springframework/cloud/appbroker/autoconfigure/DynamicCatalogServiceAutoConfigurationTest.java#L89-L107

ps: I was about to submit an issue to https://github.com/spring-projects/spring-boot/issues to suggest documentation enhancement to warn of such limitation in ApplicationContext, and to ask for ways to turn on support for @ConfigurationProperties. Following guidance at https://raw.githubusercontent.com/spring-projects/spring-boot/master/.github/ISSUE_TEMPLATE.md, I'm first making sure here I'm not misunderstanding the problem.


Solution

  • As far as I can tell, none of the classes involved in your test enable configuration property binding. As a result, no properties are bound to ServiceDefinitionMapperProperties. You can enable configuration property binding using @EnableConfigurationProperties. A typical place to add it would be on DynamicCatalogServiceAutoConfiguration as its serviceDefinitionMapperProperties bean relies on configuration properties being enabled.