在测试中自发启动 spring 启动上下文

Spontaneous up spring boot context in test

我在深入研究 spring TestContext 配置时遇到 spring-boot-test 问题。

示例项目:github example project

我有三个 Spring 配置和一些 bean(Config1 - 重量级配置,我需要缓存它)

我在上下文中使用 @ContextHierarchy 作为单独的配置,我希望 Config1 只会加载一次。 (使用@ContextHierarchy 因为我没有在 spring-boot-test 中找到类似物)

完整代码:

@ContextHierarchy({
    @ContextConfiguration(classes = {Config1.class}),
    @ContextConfiguration(classes = {Config2.class}),
})

如果我运行测试,Config1真的被缓存了!但是,我看到以下内容:

Started ConfigTest1

两次 并且

Started ConfigTest2

只有一次。在我看来,这是可能的,因为 ConfigTest1 已经缓存为 TestContext(它发生了,因为 ConfigTest1ConfigTest2 包含在同一个包中)

这意味着 spring 启动我的 spring 上下文三次!为什么? 在日志中看到spring三次开机标志:

  .   ____          _            __ _ _
 /\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.2.RELEASE)

这种行为是什么意思?这是错误还是功能?也许我做错了什么?

更新1:

非常感谢。但是,如果我在两个测试 类 中以不同的顺序在 @SpringBootTest 中设置属性(或 类)——不会缓存任何配置 :(

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextHierarchy({
    @ContextConfiguration(classes = {Config1.class}),
    @ContextConfiguration(classes = {Config2.class}),
})
public class ConfigTest1 {

@RunWith(SpringRunner.class)
@SpringBootTest(properties = "property1=1")
@ContextHierarchy({
    @ContextConfiguration(classes = {Config1.class}),
    @ContextConfiguration(classes = {Config3.class}),
})
public class ConfigTest2 {

如果没有属性 – config1 真的会被缓存!在这种情况下——没有缓存

一切正常!

您只是感到困惑,因为 Spring Boot 记录了加载 ApplicationContext 的测试 class 的名称。因此,您会在日志中看到两次 ConfigTest1,因为为该测试加载了两个上下文 class.

如果将 logging.level.org.springframework.test.context.cache=debug 添加到 application.properties,您将看到以下日志输出。

DEBUG ... c.DefaultCacheAwareContextLoaderDelegate : Storing ApplicationContext in cache under key [[WebMergedContextConfiguration@7a765367 testClass = ConfigTest1, locations = '{}', classes = '{class spring.test.mistake.delete.Config1}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.SpringBootTestContextCustomizer@643b1d11, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@6d00a15d, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@475530b9], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]]
DEBUG ... c.DefaultCacheAwareContextLoaderDelegate : Storing ApplicationContext in cache under key [[WebMergedContextConfiguration@52feb982 testClass = ConfigTest1, locations = '{}', classes = '{class spring.test.mistake.delete.Config2}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.SpringBootTestContextCustomizer@643b1d11, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@6d00a15d, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@475530b9], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [WebMergedContextConfiguration@7a765367 testClass = ConfigTest1, locations = '{}', classes = '{class spring.test.mistake.delete.Config1}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.SpringBootTestContextCustomizer@643b1d11, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@6d00a15d, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@475530b9], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]]]
DEBUG ... c.DefaultCacheAwareContextLoaderDelegate : Storing ApplicationContext in cache under key [[WebMergedContextConfiguration@5ddcc487 testClass = ConfigTest2, locations = '{}', classes = '{class spring.test.mistake.delete.Config3}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.SpringBootTestContextCustomizer@643b1d11, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@6d00a15d, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@475530b9], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [WebMergedContextConfiguration@44c73c26 testClass = ConfigTest2, locations = '{}', classes = '{class spring.test.mistake.delete.Config1}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.SpringBootTestContextCustomizer@643b1d11, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@6d00a15d, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@475530b9], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]]]
DEBUG ... org.springframework.test.context.cache   : Spring test ApplicationContext cache statistics: [DefaultContextCache@478db956 size = 3, maxSize = 32, parentContextCount = 1, hitCount = 11, missCount = 3]

因此,实际上只加载了三个上下文,即您期望的三个。