Как тестировать классы с @ConfigurationProperties и @Autowired

Я хочу протестировать небольшие части приложения, которые полагаются на свойства, загруженные с помощью @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());
    }
}

Класс конфигурации:

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

Класс настроек:

public class TestSettings {
    private String property;

    public String getProperty() {
        return property;
    }

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

Файл свойств в папке ресурсов содержит запись:

test.property=TEST_PROPERTY

В моей текущей конфигурации config не является нулевым, но поля не доступны. Причина, по которой поля не являются полями, должна быть связана с тем, что я использую не Springboot, а Spring. Так какой же будет способ Springboot для его запуска?

Редактирование: Причина, по которой я хочу сделать это: у меня есть анализатор, который анализирует текстовые файлы, используемые регулярные выражения хранятся в файле свойств. Чтобы проверить это, я хотел бы загрузить только свойства, необходимые для этого синтаксического анализатора, которые находятся в примере над TestSettings.

Читая комментарии, я уже заметил, что это больше не модульные тесты. Однако использование полной конфигурации загрузки Spring для этого небольшого теста кажется мне слишком сложным. Вот почему я спросил, есть ли возможность загружать только один класс со свойствами.

Ответ 1

Пара точек:

  • Вам не нужен класс TestConfiguration в основном пакете, потому что все, что он делает, настраивает "TestSettings" bean. Вы можете сделать это просто, аннотируя сам класс TestSettings.

  • Обычно вы загружаете контекст, необходимый для теста, с помощью аннотации @SpringApplicationConfiguration, передавая имя вашего класса Application. Однако вы сказали, что не хотите загружать весь ApplicationContext (хотя это и не понятно почему), поэтому вам нужно создать специальный класс конфигурации для загрузки только для тестов. Ниже я называю это "TestConfigurationNew", чтобы избежать путаницы с классом TestConfiguration, который вы изначально имели.

  • В мире загрузки Spring все свойства обычно хранятся в файле "application.properties"; но их можно хранить в другом месте. Ниже я указал файл "SettingsTest.properties", который вы предложили. Обратите внимание, что вы можете иметь две копии этого файла, одну из которых находится в папке main/resources, а также одну в тестовой/ресурсной папке для тестирования.

Измените код следующим образом:

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(в тестовом пакете)

@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(в тестовом пакете):

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

Теперь это должно работать так, как вы хотели.

Ответ 2

Вам необходимо аннотировать ваш TestConfiguraion с помощью @EnableConfigurationProperties следующим образом:

@EnableConfigurationProperties
public class TestConfiguration {

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

Также вам нужно включить TestConfiguration.class в @ContextConfiguration из вас SettingsTest class:

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

Ответ 3

вы можете просто добавить @EnableConfigurationProperties в свой @SpringBootTest напрямую.
например:

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

Ответ 4

Если вы используете Spring Boot, теперь вам нужно только:

@RunWith(SpringRunner.class)
@SpringBootTest

Никаких дополнительных @ContextConfiguration, никаких дополнительных классов только для тестов на EnableAutoConfiguration и EnableConfigurationProperties. Вам не нужно указывать класс конфигурации для загрузки, все они будут загружены.

Но, убедитесь, что записи свойств, которые вы хотите прочитать в main/resources/application.yml, также присутствуют в test/resources/application.yml. Повторение неизбежно.


Другой способ:

  1. Определите класс конфигурации только для тестов вместе с MyApplicationTest.java на том же уровне. Этот класс может быть пустым.

Как:

@EnableAutoConfiguration
@EnableConfigurationProperties(value = {
        ConnectionPoolConfig.class
})
public class MyApplicationTestConfiguration {
}
  1. И, в классе, чтобы загрузить конфигурацию автоматической проводки.

Как:

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

    @Autowired
    private ConnectionPoolConfig config;

По сути, вы:

  • используйте определенную конфигурацию для @EnableConfigurationProperties и @EnableAutoConfiguration, перечисляя все файлы @ConfigurationProperties, которые вы хотите загрузить
  • в тестовом классе вы загружаете этот файл конфигурации тестов с классом инициализатора, определенным Spring для загрузки файла application.yml.

И поместите значения для загрузки в test/resources/application.yml. Повторение неизбежно. Если вам нужно загрузить другой файл, используйте @TestProperties() с указанием местоположения. Примечание: @TestProperties поддерживает только файлы .properties.


Оба способа работают для значений загрузки класса конфигурации

  • либо из application.yml/application.properties
  • или из другого файла свойств, указанного в PropertySource, например @PropertySource(value = "classpath:threadpool.properties")

Важно

Последние заметки из Spring doc, согласно здесь

Некоторые люди используют Project Lombok для автоматического добавления методов получения и установки. Убедитесь, что Lombok не генерирует какой-либо конкретный конструктор для такого типа, так как он автоматически используется контейнером для создания экземпляра объекта.

Наконец, рассматриваются только стандартные свойства Java Bean, и привязка к статическим свойствам не поддерживается.

Это означает, что если у вас есть [email protected] без @NoArgsConstructor или @AllArgsConstructor, внедрение свойств не произойдет, потому что он видит только невидимый конструктор, созданный @Builder. Так что не забудьте использовать ни один, или все эти аннотации!