В моем проекте 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-компонента, более близкое к тестируемому классу. Однако, похоже, это не так.
Итак, вот мои вопросы:
@DoeJohnson: Внедрение bean-компонента в качестве MockBean решило проблемы, поскольку затем я мог определить фиктивное поведение в настройке и использовать только один TestConfiguration.




Я не использовал свойство 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 возвращает реальный экземпляр.
Я думаю, проблема здесь в том, что включение ContextConfiguration сводит на нет (частично) эффект @SpringBootTest. @SpringBootTest имеет эффект поиска @SpringBootConfiguration в вашем приложении (я полагаю, начиная с того же пакета). Однако, если применяется ContextConfiguration, то конфигурации загружаются оттуда.
Другими словами: поскольку в вашем тесте есть ContextConfiguration, сканирование классов @Configuration отключено, а TestConfiguration не загружен.
Я не думаю, что у меня есть полное представление о вашей настройке конфигурации, поэтому я не могу рекомендовать здесь лучшую практику, но быстрый способ исправить это - добавить TestConfiguration к вашему ContextConfiguration в вашем тесте. Убедитесь, что вы добавили его последним, чтобы он переопределил определения bean-компонентов в двух других конфигурациях.
Другая вещь, с которой работает мог бы, - это полное удаление @ContextConfiguration и разрешение сканированию SpringBootApplication делать свое дело - вот где может применяться то, что вы сказали о наиболее близком определении bean.
Уточненный вопрос. Размещение двух файлов конфигурации на @SpringBootTest и удаление @ContextConfiguration не имеет значения, поскольку TestConfiguration обнаруживается сканированием пакетов, и эту конфигурацию не следует включать.
Спасибо за разъяснения. Я считаю, что указание классов с помощью @SpringBootTest имеет тот же эффект, что и использование ContextConfiguration - вы можете установить debug=true в своем application.properties, чтобы увидеть, какую конфигурацию использует Spring. В любом случае, похоже, что @MockBean тоже делает то, что вы хотите.
В этом случае просто не используйте @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";
}
}
}
Вы пробовали использовать специальный профиль интеграционного тестирования? Кроме того, поскольку то, что вы возвращаете из конфигурации, в любом случае является имитацией, почему бы вам не использовать
@MockBeanв своем тестовом классе?