Тест загрузки Spring с несколькими конфигурациями

В моем проекте Spring boot 2.1 у меня есть разные @Configuration для разных тестов (ConfigurationA и ConfigurationB), которые находятся в разных пакетах. Обе конфигурации определяют один и тот же набор bean-компонентов, но по-разному (имитация и реальная вещь).

Поскольку мне известно о механизме Переопределение фасоли, представленном в Spring Boot 2.1, я установил свойство: spring.main.allow-bean-definition-overriding=true.

Однако у меня есть тест со следующей настройкой следующей конфигурации и тестового класса. Сначала в производственной части находится @Configuration (я использую Maven):

package com.stackoverflow;

@Configuration
public class ProdConfiguration{
...
}

Затем в тестовой ветке есть общий Test @Configuration на том же уровне пакета:

package com.stackoverflow

@Configuration
public class TestConfiguration {
  @Bean
  public GameMap gameMap() {
    return Mockito.mock(GameMap.class);
  }
}

А в подпакете у меня еще один @Configuration:

package com.stackoverflow.impl;

@Configuration
public class RealMapTestConfiguration {
  @Bean
  public GameMap gameMap() {
    return new GameMap("testMap.json");
  }
}

И, конечно же, есть тест, который меня беспокоит:

package com.stackoverflow.impl;

@ExtendWith(SpringExtension.class)
@SpringBootTest
@ContextConfiguration(classes = {RealMapTestConfiguration.class, ProdConfiguration.class})
@ActiveProfiles("bug") // spring.main.allow-bean-definition-overriding=true
public class MapImageServiceIT {
  @Autowired
  private GameMap map;
} 

Оказалось, что введенный в мой тест GameMap - это фиктивный экземпляр из TestConfiguration, а не реальный экземпляр из RealMapTestConfiguration. На данный момент в моем тесте у меня есть конфигурация от ProdConfiguration и TestConfiguration, когда я хотел ProdConfiguration и RealMapTestConfiguration. Поскольку компоненты, определенные в ProdConfiguration и *TestConfiguration, различны, комбинация работает, но TestConfiguration и RealMapTestConfiguration определяют то же самое. Кажется, что TestConfiguration определяется сканированием компонентов, поскольку он находится в том же пакете, что и ProdConfiguration. У меня сложилось впечатление, что при переопределении bean-компонентов предпочтительнее будет определение bean-компонента, более близкое к тестируемому классу. Однако, похоже, это не так.

Итак, вот мои вопросы:

  1. Каков порядок переопределения бобов? Какой bean-компонент переопределяет какой?
  2. Как получить правильный экземпляр в моем тесте (использование другого имени bean-компонента не является вариантом, поскольку на самом деле внедренный bean-компонент не используется напрямую в тесте, а в службе, которую использует тест, и на нем нет квалификатора .)

Вы пробовали использовать специальный профиль интеграционного тестирования? Кроме того, поскольку то, что вы возвращаете из конфигурации, в любом случае является имитацией, почему бы вам не использовать @MockBean в своем тестовом классе?

Doe Johnson 09.12.2018 08:08

@DoeJohnson: Внедрение bean-компонента в качестве MockBean решило проблемы, поскольку затем я мог определить фиктивное поведение в настройке и использовать только один TestConfiguration.

hotzst 09.12.2018 08:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
2
6 444
3

Ответы 3

Я не использовал свойство spring.main.allow-bean-definition-overriding=true, но указание конкретной конфигурации в тестовом классе отлично сработало для меня как способ переключения между объектами в разных тестах.

Ты говоришь...

It turns out that the injected GameMap into my test is a mock instance from TestConfiguration instead of the real thing from RealMapTestConfiguration.

Но RealMapTestConfiguration возвращает макет

package com.stackoverflow.impl;

@Configuration
public class RealMapTestConfiguration {
  @Bean
  public GameMap gameMap() {
    return Mockito.mock(GameMap.class);
  }
}

Примеры кода были неверными: TestConfiguration возвращает фиктивный экземпляр, а RealMapTestConfiguration возвращает реальный экземпляр.

hotzst 09.12.2018 07:48

Я думаю, проблема здесь в том, что включение ContextConfiguration сводит на нет (частично) эффект @SpringBootTest. @SpringBootTest имеет эффект поиска @SpringBootConfiguration в вашем приложении (я полагаю, начиная с того же пакета). Однако, если применяется ContextConfiguration, то конфигурации загружаются оттуда.

Другими словами: поскольку в вашем тесте есть ContextConfiguration, сканирование классов @Configuration отключено, а TestConfiguration не загружен.

Я не думаю, что у меня есть полное представление о вашей настройке конфигурации, поэтому я не могу рекомендовать здесь лучшую практику, но быстрый способ исправить это - добавить TestConfiguration к вашему ContextConfiguration в вашем тесте. Убедитесь, что вы добавили его последним, чтобы он переопределил определения bean-компонентов в двух других конфигурациях.

Другая вещь, с которой работает мог бы, - это полное удаление @ContextConfiguration и разрешение сканированию SpringBootApplication делать свое дело - вот где может применяться то, что вы сказали о наиболее близком определении bean.

Уточненный вопрос. Размещение двух файлов конфигурации на @SpringBootTest и удаление @ContextConfiguration не имеет значения, поскольку TestConfiguration обнаруживается сканированием пакетов, и эту конфигурацию не следует включать.

hotzst 09.12.2018 07:42

Спасибо за разъяснения. Я считаю, что указание классов с помощью @SpringBootTest имеет тот же эффект, что и использование ContextConfiguration - вы можете установить debug=true в своем application.properties, чтобы увидеть, какую конфигурацию использует Spring. В любом случае, похоже, что @MockBean тоже делает то, что вы хотите.

akhaku 10.12.2018 07:24

В этом случае просто не используйте @Configuration в классе конфигурации и импортируйте его в тест вручную, используя @Import, например:

@SpringBootTest
@Import(MyTest.MyTestConfig.class)
public class MyTest {

    @Autowired
    private String string;

    @Test
    public void myTest() {
        System.out.println(string);
    }

    static class MyTestConfig {
        @Bean
        public String string() {
            return "String";
        }
    }
}

Другие вопросы по теме