【问题标题】:How to test @ConfigurationProperties with ApplicationContextRunner from spring-boot-test?如何使用 spring-boot-test 中的 ApplicationContextRunner 测试 @ConfigurationProperties?
【发布时间】:2020-03-30 03:14:55
【问题描述】:

我需要测试使用 @ConfigurationProperties bean 的自动配置类。我正在使用 https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-test-autoconfig 中记录的 ApplicationContextRunner 来加快测试速度并避免在每个变体之间启动 servlet 容器。但是,使用 @AutoconfigurationProperties 注释的 bean 不会填充注入到 ApplicationContextRunner 中的值。

我怀疑我遇到了类似于https://stackoverflow.com/a/56023100/1484823 的问题

@ConfigurationProperties 不受您在测试中构建的应用程序上下文管理,尽管它们将在应用程序启动时加载,因为您的应用程序主类上有 @EnableConfigurationProperties。

如何使用 ApplicationContextRunner 启用对 @ConfigurationProperties 的支持?

这里是对应的代码

    @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");
        });
    }

失败:

 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();
    }
[...]
}

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:我正要向https://github.com/spring-projects/spring-boot/issues 提交一个问题,以建议增强文档以警告ApplicationContext 中的此类限制,并询问打开对@ConfigurationProperties 支持的方法。按照https://raw.githubusercontent.com/spring-projects/spring-boot/master/.github/ISSUE_TEMPLATE.md 的指导,我首先要确保我没有误解这个问题。

【问题讨论】:

    标签: spring-boot spring-boot-test


    【解决方案1】:

    据我所知,您的测试中涉及的所有类都没有启用配置属性绑定。因此,没有属性绑定到ServiceDefinitionMapperProperties。您可以使用@EnableConfigurationProperties 启用配置属性绑定。添加它的典型位置是DynamicCatalogServiceAutoConfiguration,因为它的serviceDefinitionMapperProperties bean 依赖于启用的配置属性。

    【讨论】:

    • 谢谢!添加 @EnableConfigurationProperties 修复了测试。我误读了之前引用的答案,认为上下文实现类不支持配置属性。抱歉吵了。
    【解决方案2】:

    如果您想在测试中填充带有 @ConfigurationProperties 类注释的 bean,并且您通常依赖带有 @EnableConfigurationProperties 注释的配置类来填充该 bean,那么您可以创建一个简单的配置类,仅用于测试:

    @ConfigurationProperties("app")
    public class ConfigProps {
        private int meaningOfLife;
    
        public int getMeaningOfLife() { return meaningOfLife; }
        public void setMeaningOfLife(int meaning) { this.meaningOfLife = meaning; }
    }
    
    class ConfigPropsTest {
    
        private final ApplicationContextRunner runner = new ApplicationContextRunner();
    
        @EnableConfigurationProperties(ConfigProps.class)
        static class TrivialConfiguration {
        }
    
        @Test
        void test() {
            runner.withUserConfiguration(TrivialConfiguration.class)
                .withPropertyValues("app.meaning-of-life=42")
                .run(context -> {
                    assertEquals(42, context.getBean(ConfigProps.class).getMeaningOfLife());
                });
        }
    
    }
    

    TrivialConfiguration 传递给ApplicationContextRunner 足以使其创建ConfigProps 并使用可用属性填充它。

    【讨论】:

    • 这是一个很好的答案 - 谢谢。您认为直接在其上设置@EnableConfigurationProperties 对类本身(例如ConfigProps)来说是不好的做法吗?我想这很糟糕,因为如果编写一个库,会希望实际的应用程序确定启用配置属性是否可以。
    • 对于阅读此答案的任何人,不要忘记公开您的属性。我遇到了同样的问题,但我的 props 上没有公共 getter/setter 访问权限,因此找不到问题!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 2019-11-22
    • 2017-07-28
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    相关资源
    最近更新 更多