Github地址html
@TestConfiguration是Spring Boot Test提供的一种工具,用它咱们能够在通常的@Configuration以外补充测试专门用的Bean或者自定义的配置。java
@TestConfiguration其实是一种@TestComponent,@TestComponent是另外一种@Component,在语义上用来指定某个Bean是专门用于测试的。git
须要特别注意,你应该使用一切办法避免在生产代码中自动扫描到@TestComponent。
若是你使用@SpringBootApplication
启动测试或者生产代码,@TestComponent会自动被排除掉,若是不是则须要像@SpringBootApplication
同样添加TypeExcludeFilter
:github
//... @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), // ...}) public @interface SpringBootApplication
@TestConfiguration和@Configuration不一样,它不会阻止@SpringBootTest去查找机制(在Chapter 1: 基本用法 - 使用Spring Boot Testing工具 - 例子4提到过),正如@TestConfiguration的javadoc所说,它只是对既有配置的一个补充。spring
因此咱们在测试代码上添加@SpringBootConfiguration,用@SpringBootTest(classes=...)
或者在同package里添加@SpringBootConfiguration类都是能够的。api
并且@TestConfiguration做为内部类的时候它是会被@SpringBootTest扫描掉的,这点和@Configuration同样。app
测试代码TestConfigurationTest:spring-boot
@SpringBootTest @SpringBootConfiguration public class TestConfigurationTest extends AbstractTestNGSpringContextTests { @Autowired private Foo foo; @Test public void testPlusCount() throws Exception { assertEquals(foo.getName(), "from test config"); } @TestConfiguration public class TestConfig { @Bean public Foo foo() { return new Foo("from test config"); } } }
@TestConfiguration可以:工具
补充额外的Bean测试
覆盖已存在的Bean
要特别注意第二点,@TestConfiguration可以直接覆盖已存在的Bean,这一点正常的@Configuration是作不到的。
咱们先提供了一个正常的@Configuration(Config):
@Configuration public class Config { @Bean public Foo foo() { return new Foo("from config"); } }
又提供了一个@TestConfiguration,在里面覆盖了foo
Bean,而且提供了foo2
Bean(TestConfig):
@TestConfiguration public class TestConfig { // 这里不须要@Primary之类的机制,直接就可以覆盖 @Bean public Foo foo() { return new Foo("from test config"); } @Bean public Foo foo2() { return new Foo("from test config2"); } }
@SpringBootTest(classes = { Config.class, TestConfig.class }) public class TestConfigurationTest extends AbstractTestNGSpringContextTests { @Qualifier("foo") @Autowired private Foo foo; @Qualifier("foo2") @Autowired private Foo foo2; @Test public void testPlusCount() throws Exception { assertEquals(foo.getName(), "from test config"); assertEquals(foo2.getName(), "from test config2"); } }
再查看输出的日志,就会发现Auto Configuration已经关闭。
在上面的这个例子里的TestConfig是会被@ComponentScan扫描到的,若是要避免被扫描到,在本文开头已经提到过了。
先来看一下没有作任何过滤的情形,咱们先提供了一个@SpringBootConfiguration(IncludeConfig):
@SpringBootConfiguration @ComponentScan public interface IncludeConfig { }
而后有个测试代码引用了它(TestConfigIncludedTest):
@SpringBootTest(classes = IncludeConfig.class) public class TestConfigIncludedTest extends AbstractTestNGSpringContextTests { @Autowired(required = false) private TestConfig testConfig; @Test public void testPlusCount() throws Exception { assertNotNull(testConfig); } }
从这段代码能够看到TestConfig
被加载了。
如今咱们使用TypeExcludeFilter来过滤@TestConfiguration(ExcludeConfig1):
@SpringBootConfiguration @ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class) }) public interface ExcludeConfig1 { }
再来看看结果(TestConfigExclude_1_Test):
@SpringBootTest(classes = ExcludeConfig1.class) public class TestConfigExclude_1_Test extends AbstractTestNGSpringContextTests { @Autowired(required = false) private TestConfig testConfig; @Test public void test() throws Exception { assertNull(testConfig); } }
还能够用@SpringBootApplication来排除TestConfig
(ExcludeConfig2):
@SpringBootApplication public interface ExcludeConfig2 { }
看看结果(TestConfigExclude_2_Test):
@SpringBootTest(classes = ExcludeConfig2.class) public class TestConfigExclude_2_Test extends AbstractTestNGSpringContextTests { @Autowired(required = false) private TestConfig testConfig; @Test public void testPlusCount() throws Exception { assertNull(testConfig); } }