Spring boot 对于@SpringBootTest,@TestConfiguration类的导入不执行任何操作,而@ContextConfiguration会按预期重写

Spring boot 对于@SpringBootTest,@TestConfiguration类的导入不执行任何操作,而@ContextConfiguration会按预期重写,spring-boot,spring-boot-test,Spring Boot,Spring Boot Test,考虑以下集成测试注释: @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, properties = "spring.main.allow-bean-definition-overriding=true") @ContextConfiguration(classes = {WorkerTestConfig.class})

考虑以下集成测试注释:

@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会后退,而WorkertTestConfig中的bean会被使用;每当我使用
@Import
时,真实bean仍会被创建,并且测试失败

WorkerTestConfig
本身尽可能简单:

@TestConfiguration
public class WorkerTestConfig {

    @Primary
    @Bean
    public ScheduledExecutorService taskExecutor() {
        return DirectExecutorFactory.createSameThreadExecutor();
    }
}
有人能解释一下@SpringBootTest注解的另一个神奇行为吗?如果您重现相同的行为,请确认,以便我可以转到问题跟踪程序,因为我看到人们在这里使用
@Import
@springbootest
,因此在spring boot文档中没有任何禁止它的内容:

对正在发生的事情完全困惑不解

版本:2.1.2.1发布

更新:

还尝试删除真正的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;
现在,如果调试应用程序,在处理配置类时将获得额外的输出

使用
注释属性而不使用
@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]
当您使用不带
classes
属性的
@Import
时,您将获得:

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]
第一个版本在
SomeTestSecondConfiguration
之前加载
WorkerConfig
,而第二个版本在
WorkerConfig
之前加载
SomeTestSecondConfiguration

您还将注意到,第二个版本有一个
importContextCustomizer$importConfiguration
类,它触发了额外的导入

如果查看
SpringBootTestContextBootstrapper
,您可以在
getOrFindConfigurationClasses
方法中看到,已定义了排序,并且附加的测试类将始终列在主配置之后

tl;dr如果需要定义顺序,请使用
classes
属性。如果您想添加额外的bean,并且不想覆盖任何内容,请使用
@Import


您可能还想看看
@MockBean
,它提供了一种更健壮的方法来用mock替换bean。

@TestConfiguration类将自动注册,如果它们是嵌套类。您尝试过这个吗?@ck1 WorkerConfig与测试的级别5相同,它们在兄弟包中。我不希望它是嵌套类,因为它具有跨集成测试重用的巨大潜力。啊,你编辑了,是的,就像我说的,我想重用这个配置。我收回我的答案。您是正确的:
@Import
不适用于顶级的
@TestConfiguration
类,尽管文档表明它应该适用。我假设第46.3.3节中
@Import(mytestscoconfiguration.class)
中的
mytestscoconfiguration
中的
mytestscoconfiguration
引用了一个用
@TestConfiguration
注释的类,我将参考春季发行的SOtracker@phil.webb. 感谢您对注释的清晰解释和意图,以及查看加载内容的简便技巧。唯一让我困惑的是,“ScheduledExecutorService”遵循您解释的规则和顺序。“OriginalInterface”在导入时始终由testconfigurationbean覆盖。请验证第二种方法“checkWhosGreeting”好吗。当我使用条件断点时,我可以看到在测试一之后加载了Original,但它并没有覆盖测试一,ScheduledExecutorService bean的工作方式与标准bean一致:)