Интеграционное тестирование с использованием @SpringBootTest не выбирает автоконфигурирование библиотеки, настроенной с использованием spring.factories - PullRequest
1 голос
/ 14 июня 2019

У нас есть библиотека, для автоматической настройки библиотеки мы используем файл spring.factories в (src/main/resources/META-INF), который предоставляет классы для автоматической настройки моей библиотеки.

Ссылка: https://docs.spring.io/spring-boot/docs/1.4.0.M3/reference/htmlsingle/#boot-features-custom-starter

У меня есть настройки ниже в файле spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.x.y.PubSubConfig

Насколько я понимаю, spring.factories является альтернативой для настройки библиотеки и назначения сервера, аналогично @SpringBootApplication в обычном приложении.

Я делаю интеграцию с использованием @SpringBootTest, я ожидаю, что мой контекст будет настроен из классов конфигурации, предоставляемых spring.factories. Когда я запускаю эти тесты, весна не идентифицирует spring.factories и выдает ошибку

java.lang.IllegalStateException: невозможно найти @SpringBootConfiguration, вам нужно использовать @ContextConfiguration или @SpringBootTest (classes = ...) с вашим тестом

  • Если я аннотирую свой PubSubConfig с помощью SpringBootApplication, тогда мои интеграционные тесты работают отлично, но, поскольку это библиотека, я не хочу этого делать.
  • Если я предоставляю свой класс конфигурации специально с использованием @SpringBootTest(classes = PubSubConfig.class), мои тесты выполняются нормально.

Теперь я пытаюсь понять, почему мне нужно сделать что-то одно из вышеперечисленных специально, поскольку spring.factories отвечает за автоматическую настройку

1 Ответ

1 голос
/ 14 июня 2019

@SpringBootTest предназначен для тестирования приложения Spring Boot.Без какой-либо другой конфигурации он ищет класс, аннотированный или мета-аннотированный @SpringBootConfiguration.Обычно это основной класс вашего приложения, который аннотирован @SpringBootApplication (который мета-аннотирован @SpringBootConfiguration. @SpringBootApplication также мета-аннотирован @EnableAutoConfiguration, поэтому, когда @SpringBootTest находит @SpringBootApplication -аннотированный классавтоконфигурация включена для тестов так же, как и при выполнении самого приложения.

Когда вы пытаетесь протестировать автоконфигурацию, нет класса, помеченного @SpringBootConfiguration, поэтому вы видите этоошибка:

java.lang.IllegalStateException: невозможно найти @SpringBootConfiguration, необходимо использовать @ContextConfiguration или @SpringBootTest (classes = ...) с вашим тестом

Как вы заметили, вы могли бы решить проблему, пометив PubSubConfig с помощью @SpringBootApplication, но вам не следует делать это, так как это библиотека. @SpringBootTest(classes=PubSubConfig.class) - лучшее решение, поскольку избегает изменения основного кода вашей библиотеки, однакоон по-прежнему не идеален, поскольку @SpringBootTest действительно нацелен на тестирование приложения Spring Boot, а не на библиотеку, предназначенную для использования в приложении Spring Bootication.

Вместо использования @SpringBootTest я бы рекомендовал использовать ApplicationContextRunner.Как следует из названия, он предназначен для запуска контекста приложения.Он предоставляет методы компоновщика для автоконфигурации конфигурации и пользовательской конфигурации, которые следует использовать для создания контекста, настройки свойств и т. Д. Он также предоставляет устанавливаемый контекст приложения, который позволяет легко проверить, что ожидаемые bean-компоненты были и не были определены,Он широко используется в собственных тестах Spring Boot для автоматической настройки.

Вот пример, взятый из собственных тестов Spring Boot для автоматической настройки DataSource:

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
        .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))
        .withPropertyValues("spring.datasource.initialization-mode=never",
                "spring.datasource.url:jdbc:hsqldb:mem:testdb-" + new Random().nextInt());

@Test
public void testDefaultDataSourceExists() {
    this.contextRunner.run((context) -> assertThat(context).hasSingleBean(DataSource.class));
}
...