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