Java 如何使用 @ConfigurationProperties 和 @Autowired 测试类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31745168/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:33:10  来源:igfitidea点击:

How to test Classes with @ConfigurationProperties and @Autowired

javapropertiesspring-boot

提问by IndianerJones

I want to test small parts of the application that rely on properties loaded with @Autowiredand @ConfigurationProperties. I am looking for a solution loading only the required properties and not always the whole ApplicationContext. Here as reduced example:

我想测试依赖于加载的属性的应用程序的一小部分@Autowired@ConfigurationProperties。我正在寻找一种仅加载所需属性而不总是加载整个ApplicationContext. 这里作为简化的例子:

@TestPropertySource(locations = "/SettingsTest.properties")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestSettings.class, TestConfiguration.class})
public class SettingsTest {
    @Autowired
    TestConfiguration config;

    @Test
    public void testConfig(){
        Assert.assertEquals("TEST_PROPERTY", config.settings().getProperty());
    }
}

Configuration Class:

配置类:

public class TestConfiguration {
    @Bean
    @ConfigurationProperties(prefix = "test")
    public TestSettings settings (){
        return new TestSettings();
    }
}

Settings Class:

设置类:

public class TestSettings {
    private String property;

    public String getProperty() {
        return property;
    }

    public void setProperty(String property) {
        this.property = property;
    }
}

The properties file in the resource folder contains the entry:

资源文件夹中的属性文件包含以下条目:

test.property=TEST_PROPERTY

In my current setup config is not null, but no fields are available. The reason the fields are not field should have something to do with the fact that I am not using Springboot but Spring. So what would be the Springboot way to get this running?

在我当前的设置中,配置不为空,但没有可用的字段。字段不是字段的原因应该与我使用的不是 Springboot 而是 Spring 的事实有关。那么 Springboot 的运行方式是什么?

edit:The reason why I want to do this is: I have a parser that parses Textfiles, the regular expressions used are stored in a properties file. To test this I would like to load only the properties needed for this parser which are in the exaple above the TestSettings.

编辑:我要这样做的原因是:我有一个解析文本文件的解析器,使用的正则表达式存储在属性文件中。为了对此进行测试,我只想加载此解析器所需的属性,这些属性位于TestSettings上方的示例中

While reading the comments I already noticed that this are no Unit tests anymore. However using the full Spring boot configuration for this small test seems a bit too much to me. That's why I asked if there is a posibilty to load only the one class with properties.

在阅读评论时,我已经注意到这不再是单元测试。然而,在这个小测试中使用完整的 Spring 启动配置对我来说似乎有点过分。这就是为什么我问是否有可能只加载一个具有属性的类。

采纳答案by David H

A couple points:

几点:

  1. You don't need a "TestConfiguration" class in your main package, because all it's doing is configuring the "TestSettings" bean. You can do this simply by annotating the TestSettings class itself.

  2. Normally you would load the context you need for the test using the @SpringApplicationConfigurationannotation, passing the name of your Application class. However, you said you don't want to load the whole ApplicationContext (though it's not clear why), so you need to create a special configuration class to do the loading only for tests. Below I call it "TestConfigurationNew" to avoid confusion with the TestConfiguration class that you had originally.

  3. In the Spring Boot world, all properties are generally kept in the "application.properties" file; but it is possible to store them elsewhere. Below, I have specified the "SettingsTest.properties" file that you proposed. Note that you can have two copies of this file, the one in the main/resources folder, and the one in the test/resources folder for testing.

  1. 您的主包中不需要“TestConfiguration”类,因为它所做的只是配置“TestSettings”bean。您可以简单地通过注释 TestSettings 类本身来做到这一点。

  2. 通常,您将使用@SpringApplicationConfiguration批注加载测试所需的上下文,传递应用程序类的名称。但是,你说你不想加载整个ApplicationContext(虽然不清楚为什么),所以你需要创建一个特殊的配置类来只为测试加载。下面我将其称为“TestConfigurationNew”以避免与您最初拥有的 TestConfiguration 类混淆。

  3. 在 Spring Boot 的世界里,所有的属性一般都保存在“application.properties”文件中;但可以将它们存储在其他地方。下面,我指定了您建议的“SettingsTest.properties”文件。请注意,您可以拥有此文件的两份副本,一份在 main/resources 文件夹中,另一份在 test/resources 文件夹中用于测试。

Change the code as follows:

更改代码如下:

TestSettings.java (in main package)

TestSettings.java(在主包中)

@Configuration
@ConfigurationProperties(prefix="test", locations = "classpath:SettingsTest.properties")
public class TestSettings {

    private String property;

    public String getProperty() {
        return property;
    }

    public void setProperty(String property) {
        this.property = property;
    }
}

SettingsTest.java (in test package)

SettingsTest.java(在测试包中)

@TestPropertySource(locations="classpath:SettingsTest.properties")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfigurationNew.class)
public class SettingsTest {

    @Autowired
    TestSettings settings;

    @Test
    public void testConfig(){
        Assert.assertEquals("TEST_PROPERTY", settings.getProperty());
    }
}

TestConfigurationNew.java (in test package):

TestConfigurationNew.java(在测试包中):

@EnableAutoConfiguration
@ComponentScan(basePackages = { "my.package.main" })
@Configuration
public class TestConfigurationNew {
}

This should now work the way you wanted.

这现在应该按照您想要的方式工作。

回答by Stepan Kolesnik

You need to annotate your TestConfiguraion with @EnableConfigurationPropertiesas follows:

您需要使用以下注释对您的 TestConfiguraion 进行注释@EnableConfigurationProperties

@EnableConfigurationProperties
public class TestConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "test")
    public TestSettings settings (){
        return new TestSettings();
    }
}

Also you only need to include TestConfiguration.classin @ContextConfigurationof you SettingsTestclass:

此外,您只需要包含TestConfiguration.class@ContextConfiguration您的SettingsTest课程中:

@TestPropertySource(locations = "/SettingsTest.properties")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
public class SettingsTest {
...

回答by Jason

you can actually just add @EnableConfigurationProperties to your @SpringBootTest directly.
eg:

您实际上可以直接将 @EnableConfigurationProperties 添加到您的 @SpringBootTest 中。
例如:

@ActiveProfiles("test")
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestConfiguration.class)
@EnableConfigurationProperties
...

回答by WesternGun

If you use Spring Boot, now you only need:

如果你使用 Spring Boot,现在你只需要:

@RunWith(SpringRunner.class)
@SpringBootTest

No extra @ContextConfiguration, no extra class only for tests to EnableAutoConfigurationand EnableConfigurationProperties. You don't have to specify the configuration class to load, they will all be loaded.

没有额外的@ContextConfiguration,没有额外的类只用于测试EnableAutoConfigurationEnableConfigurationProperties。您不必指定要加载的配置类,它们都会被加载。

But, ensure the properties entries you want to read in main/resources/application.ymlis also present in test/resources/application.yml. Repetition is unavoidable.

但是,请确保您要读取的属性条目main/resources/application.yml也存在于test/resources/application.yml. 重复是不可避免的。



Another way is:

另一种方式是:

  1. Define a class of configuration only for tests, along with MyApplicationTest.java, at the same level. This class can be empty.
  1. 定义一类仅用于测试的配置,以及MyApplicationTest.java, 在同一级别。这个类可以是空的。

Like:

喜欢:

@EnableAutoConfiguration
@EnableConfigurationProperties(value = {
        ConnectionPoolConfig.class
})
public class MyApplicationTestConfiguration {
}
  1. And, in the class to load the autowired configuration.
  1. 并且,在类中加载自动装配的配置。

Like:

喜欢:

@RunWith(SpringRunner.class)
//@SpringBootTest // the first, easy way
@ContextConfiguration(classes = MyApplicationTestConfiguration.class,
        initializers = ConfigFileApplicationContextInitializer.class)
public class ConnectionPoolConfigTest {

    @Autowired
    private ConnectionPoolConfig config;

Basically, you:

基本上,您:

  • use a specific configuration to @EnableConfigurationPropertiesand @EnableAutoConfiguration, listing all the @ConfigurationPropertiesfiles you want to load
  • in the test class, you load this configuration file of tests, with an initializer class defined by Spring to load application.ymlfile.
  • @EnableConfigurationProperties和使用特定配置@EnableAutoConfiguration,列出@ConfigurationProperties要加载的所有文件
  • 在测试类中,你加载这个测试的配置文件,用 Spring 定义的初始化类来加载application.yml文件。

And, put the values to load in test/resources/application.yml. Repetition is unavoidable. If you need load another file, use @TestProperties()with a location. Note: @TestPropertiesonly supports .propertiesfiles.

并且,将要加载的值放入test/resources/application.yml. 重复是不可避免的。如果您需要加载另一个文件,请使用@TestProperties()一个位置。注意@TestProperties仅支持.properties文件。



Both way works for configuration class loading values

两种方式都适用于配置类加载值

  • either from application.yml/application.properties
  • or from another properties file, specified by PropertySource, like @PropertySource(value = "classpath:threadpool.properties")
  • 要么来自application.yml/application.properties
  • 或来自另一个属性文件,由 指定PropertySource,例如@PropertySource(value = "classpath:threadpool.properties")


Important

重要的

Last notes from Spring doc, as per here

Spring 文档的最后注释,如此处所示

Some people use Project Lombok to add getters and setters automatically. Make sure that Lombok does not generate any particular constructor for such a type, as it is used automatically by the container to instantiate the object.

Finally, only standard Java Bean properties are considered and binding on static properties is not supported.

有些人使用 Project Lombok 自动添加 getter 和 setter。确保 Lombok 不会为此类类型生成任何特定的构造函数,因为容器会自动使用它来实例化对象。

最后,只考虑标准 Java Bean 属性,不支持静态属性绑定。

That means, if you have lombok.@Builderwithout @NoArgsConstructornor @AllArgsConstructor, properties injection will not happen because it only sees the invisible constructor created by @Builder. So, be sure to use none, or all of these annotations!

这意味着,如果lombok.@Builder没有@NoArgsConstructorno@AllArgsConstructor,则不会发生属性注入,因为它只会看到由@Builder. 因此,请确保不使用任何注释,或者全部使用这些注释!