spring-boot - 对于@SpringBootTest @TestConfiguration 类的@Import 什么都不做,而@ContextConfiguration 按预期覆盖
问题描述
考虑以下集成测试注释:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE,
properties = "spring.main.allow-bean-definition-overriding=true")
@ContextConfiguration(classes = {WorkerTestConfig.class})
//@Import(value = {WorkerTestConfig.class})
@ActiveProfiles({"dev","test"})
public class NumberServiceITest {
WorkestTestConfig 的作用是在集成启动期间覆盖真正的 bean/bean 集,每当我使用@ContextConfiguration
真正的 bean 并使用来自 WorkerTestConfig 的 bean 时,每当我使用@Import
真正的 bean 时,仍然会创建并通过测试。
WorkerTestConfig
本身是尽可能微不足道的:
@TestConfiguration
public class WorkerTestConfig {
@Primary
@Bean
public ScheduledExecutorService taskExecutor() {
return DirectExecutorFactory.createSameThreadExecutor();
}
}
谁能解释@SpringBootTest注释的另一个神奇行为?如果您重现相同的行为,请确认以便我可以去问题跟踪器,因为我已经看到人们在 SO 上使用@Import
with@SpringBootTest
并且在 Spring Boot 文档中没有任何禁止它:
https ://docs.spring.io/spring-boot/ docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications- exclude-config
完全不知道发生了什么。
版本:2.1.2.RELEASE
更新:
还尝试删除真正的 bean 以查看问题是否只是覆盖,但@Import
注释只是死在水中,不起作用 -> 甚至无法创建 bean,@ContextConfiguration 具有附加/覆盖行为,导入在全部。注释的完全限定导入是:import org.springframework.context.annotation.Import;
也试图从改变@TestConfiguration
到@Configuration
只是为了它,根本没有。死的。
更新 2:
虽然@Import
适用于标准弹簧测试:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {Some.class,
Some2WhichDependsOnWorkerTestConfig.class})
@Import(WorkerTestConfig.class)
@ActiveProfiles("test")
public class SomeOtherTest {
解决方案
@Import
未定义在测试中使用类时处理它们的顺序。添加测试功能的@Import
主要目的是允许轻松注册其他bean,无意将其用于替换bean 定义。
如果您想深入了解杂草并确切了解发生了什么,您可以打开ConfigurationClassParser
并在doProcessConfigurationClass
. 添加以下条件代码:
System.err.println(configClass);
return false;
现在,如果您调试应用程序,您将在处理配置类时获得附加输出。
当您使用classes
不带注释的属性时,@Import
您会看到:
ConfigurationClass: beanName 'demoImportBugApplication', com.example.demoimportbug.DemoImportBugApplication
ConfigurationClass: beanName 'original', class path resource [com/example/demoimportbug/first/Original.class]
ConfigurationClass: beanName 'workerConfig', class path resource [com/example/demoimportbug/first/WorkerConfig.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/scheduling/annotation/ProxyAsyncConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/scheduling/annotation/ProxyAsyncConfiguration.class]
ConfigurationClass: beanName 'someTestSecondConfiguration', com.example.demoimportbug.second.SomeTestSecondConfiguration
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/context/PropertyPlaceholderAutoConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/cache/GenericCacheConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/cache/SimpleCacheConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/cache/NoOpCacheConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/context/ConfigurationPropertiesAutoConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/info/ProjectInfoAutoConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.class]
当您使用@Import
没有classes
属性的情况下,您将获得:
ConfigurationClass: beanName 'org.springframework.boot.test.context.ImportsContextCustomizer$ImportsConfiguration', org.springframework.boot.test.context.ImportsContextCustomizer$ImportsConfiguration
ConfigurationClass: beanName 'null', class path resource [com/example/demoimportbug/first/SomeFirstUsingSecondConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [com/example/demoimportbug/second/SomeTestSecondConfiguration.class]
ConfigurationClass: beanName 'demoImportBugApplication', com.example.demoimportbug.DemoImportBugApplication
ConfigurationClass: beanName 'original', class path resource [com/example/demoimportbug/first/Original.class]
ConfigurationClass: beanName 'workerConfig', class path resource [com/example/demoimportbug/first/WorkerConfig.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/scheduling/annotation/ProxyAsyncConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/scheduling/annotation/ProxyAsyncConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/context/PropertyPlaceholderAutoConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/cache/GenericCacheConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/cache/SimpleCacheConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/cache/NoOpCacheConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/context/ConfigurationPropertiesAutoConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/info/ProjectInfoAutoConfiguration.class]
ConfigurationClass: beanName 'null', class path resource [org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.class]
第一个版本WorkerConfig
在之前加载,SomeTestSecondConfiguration
而第二个版本SomeTestSecondConfiguration
在之前加载WorkerConfig
。
您还会注意到第二个版本有一个ImportsContextCustomizer$ImportsConfiguration
触发额外导入的类。
如果您看一下,SpringBootTestContextBootstrapper
您可以在getOrFindConfigurationClasses
方法中看到定义了排序,并且您的附加测试类将始终列在主要配置之后。
tl;dr 如果您需要定义的排序,请使用该classes
属性。如果你想添加额外的 bean 并且你不想覆盖任何东西,请使用@Import
.
您可能还想看看@MockBean
哪个提供了一种更强大的方法来用模拟替换 bean。
推荐阅读
- algorithm - 可以从 O(n2) 朴素解决方案在 O(n) 中运行的算法的泛化
- kivy - Kivy 和 KivyMD 可以在一个项目中一起使用吗?
- plot - 放大时 Gnuplot 会擦除圆圈
- ios - 相同的可选值有时为零,有时不是
- pandas - 使用 Panda 数据框创建多个 .txt 文件并将其保存为 .csv 文件
- google-apis-explorer - 无法找出原因 youtube 分析的响应始终为零
- c++ - 如何将 const struct 指针传递给 C++ 中的 setter 方法
- javascript - 带有 Firestore 集合的 Next.js 动态路由
- django - 检查在 Django 中下载媒体文件的权限
- amazon-web-services - 为什么我不能在 AWS Elastic Beanstalk 的 docker 容器内运行 X-Ray 守护程序