上下文层次结构
在编写依赖于加载的Spring ApplicationContext
的集成测试时,通常只需针对单个上下文进行测试即可。但是,有时测试针对一系列ApplicationContext
实例的层次结构进行测试是有益的,甚至是必要的。例如,如果您正在开发一个Spring MVC Web应用程序,通常会有一个由Spring的ContextLoaderListener
加载的根WebApplicationContext
和一个由Spring的DispatcherServlet
加载的子WebApplicationContext
。这导致了一个父子上下文层次结构,在根上下文中声明了共享组件和基础架构配置,并在子上下文中由特定于Web的组件使用。另一个用例可以在Spring Batch应用程序中找到,其中通常有一个提供共享批处理基础架构配置的父上下文和一个用于特定批处理作业配置的子上下文。
您可以通过在单个测试类或测试类层次结构中使用@ContextHierarchy
注解来声明上下文层次结构的配置。如果在测试类层次结构中的多个类上声明了上下文层次结构,则还可以合并或覆盖上下文层次结构中特定命名级别的上下文配置。在合并给定级别的层次结构中的配置时,配置资源类型(即XML配置文件或组件类)必须保持一致。否则,可以接受使用不同资源类型配置上下文层次结构中的不同级别。
本节中剩余的基于JUnit Jupiter的示例展示了需要使用上下文层次结构的集成测试的常见配置场景。
具有上下文层次结构的单个测试类
ControllerIntegrationTests
代表了一个典型的Spring MVC Web应用程序的集成测试场景,通过声明一个包含两个级别的上下文层次结构,一个用于根WebApplicationContext
(通过使用TestAppConfig
@Configuration
类加载)和一个用于调度程序servlet WebApplicationContext
(通过使用WebConfig
@Configuration
类加载)。被自动装配到测试实例中的WebApplicationContext
是子上下文的(即层次结构中最低的上下文)。以下清单显示了这种配置场景:
-
Java
-
Kotlin
@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextHierarchy({
@ContextConfiguration(classes = TestAppConfig.class),
@ContextConfiguration(classes = WebConfig.class)
})
class ControllerIntegrationTests {
@Autowired
WebApplicationContext wac;
// ...
}
@ExtendWith(SpringExtension::class)
@WebAppConfiguration
@ContextHierarchy(
ContextConfiguration(classes = [TestAppConfig::class]),
ContextConfiguration(classes = [WebConfig::class]))
class ControllerIntegrationTests {
@Autowired
lateinit var wac: WebApplicationContext
// ...
}
具有隐式父上下文的类层次结构
此示例中的测试类定义了一个测试类层次结构内的上下文层次结构。 AbstractWebTests
在Spring驱动的Web应用程序中声明了根WebApplicationContext
的配置。但是,请注意,AbstractWebTests
没有声明@ContextHierarchy
。因此,AbstractWebTests
的子类可以选择参与上下文层次结构或遵循@ContextConfiguration
的标准语义。 SoapWebServiceTests
和RestWebServiceTests
都扩展了AbstractWebTests
,并通过使用@ContextHierarchy
定义了一个上下文层次结构。结果是加载了三个应用程序上下文(每个@ContextConfiguration
声明加载一个),并且基于AbstractWebTests
中的配置加载的应用程序上下文被设置为每个具体子类加载的上下文的父上下文。以下清单显示了这种配置场景:
-
Java
-
Kotlin
@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml")
public abstract class AbstractWebTests {}
@ContextHierarchy(@ContextConfiguration("/spring/soap-ws-config.xml"))
public class SoapWebServiceTests extends AbstractWebTests {}
@ContextHierarchy(@ContextConfiguration("/spring/rest-ws-config.xml"))
public class RestWebServiceTests extends AbstractWebTests {}
@ExtendWith(SpringExtension::class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml")
abstract class AbstractWebTests
@ContextHierarchy(ContextConfiguration("/spring/soap-ws-config.xml"))
class SoapWebServiceTests : AbstractWebTests()
@ContextHierarchy(ContextConfiguration("/spring/rest-ws-config.xml"))
class RestWebServiceTests : AbstractWebTests()
具有合并上下文层次结构配置的类层次结构
此示例中的类展示了使用命名层次级别以合并上下文层次结构中特定级别的配置。 BaseTests
定义了两个层次级别,parent
和child
。 ExtendedTests
扩展了BaseTests
,并指示Spring TestContext Framework合并child
层次级别的上下文配置,确保在@ContextConfiguration
中声明的name
属性的名称都是child
。结果是加载了三个应用程序上下文:一个用于/app-config.xml
,一个用于/user-config.xml
,一个用于{"/user-config.xml", "/order-config.xml"}
。与前一个示例类似,从/app-config.xml
加载的应用程序上下文被设置为从/user-config.xml
和{"/user-config.xml", "/order-config.xml"}
加载的上下文的父上下文。以下清单显示了这种配置场景:
-
Java
-
Kotlin
@ExtendWith(SpringExtension.class)
@ContextHierarchy({
@ContextConfiguration(name = "parent", locations = "/app-config.xml"),
@ContextConfiguration(name = "child", locations = "/user-config.xml")
})
class BaseTests {}
@ContextHierarchy(
@ContextConfiguration(name = "child", locations = "/order-config.xml")
)
class ExtendedTests extends BaseTests {}
@ExtendWith(SpringExtension::class)
@ContextHierarchy(
ContextConfiguration(name = "parent", locations = ["/app-config.xml"]),
ContextConfiguration(name = "child", locations = ["/user-config.xml"]))
open class BaseTests {}
@ContextHierarchy(
ContextConfiguration(name = "child", locations = ["/order-config.xml"])
)
class ExtendedTests : BaseTests() {}
具有覆盖上下文层次结构配置的类层次结构
与前一个示例相比,此示例演示了如何通过在@ContextConfiguration
中将inheritLocations
标志设置为false
来覆盖上下文层次结构中给定命名级别的配置。因此,ExtendedTests
的应用程序上下文仅从/test-user-config.xml
加载,并且其父级设置为从/app-config.xml
加载的上下文。以下清单显示了此配置方案:
-
Java
-
Kotlin
@ExtendWith(SpringExtension.class)
@ContextHierarchy({
@ContextConfiguration(name = "parent", locations = "/app-config.xml"),
@ContextConfiguration(name = "child", locations = "/user-config.xml")
})
class BaseTests {}
@ContextHierarchy(
@ContextConfiguration(
name = "child",
locations = "/test-user-config.xml",
inheritLocations = false
))
class ExtendedTests extends BaseTests {}
@ExtendWith(SpringExtension::class)
@ContextHierarchy(
ContextConfiguration(name = "parent", locations = ["/app-config.xml"]),
ContextConfiguration(name = "child", locations = ["/user-config.xml"]))
open class BaseTests {}
@ContextHierarchy(
ContextConfiguration(
name = "child",
locations = ["/test-user-config.xml"],
inheritLocations = false
))
class ExtendedTests : BaseTests() {}
在上下文层次结构中使上下文变脏
如果在作为上下文层次结构的一部分配置的测试中使用@DirtiesContext ,您可以使用hierarchyMode 标志来控制上下文缓存如何清除。有关详细信息,请参阅Spring测试注释中的@DirtiesContext 讨论以及@DirtiesContext javadoc。 |