Context Hierarchies
在编写依赖于已加载 Spring ApplicationContext
的集成测试时,通常针对单个上下文进行测试就足够了。但是,有时针对 ApplicationContext
实例的层次结构进行测试是有益的甚至是必要的。例如,如果正在开发一个 Spring MVC Web 应用程序,则通常会加载由 Spring 的 ContextLoaderListener
加载的根 WebApplicationContext
和由 Spring 的 DispatcherServlet
加载的子 WebApplicationContext
。这将导致一个父级-子级上下文层次结构,在该层次结构中,共享组件和基础设施配置在根上下文中声明,并在子上下文中由特定于 Web 的组件使用。Spring Batch 应用程序也可以找到另一个用例,在该应用程序中,通常有一个提供共享批处理基础设施配置的父上下文以及用于特定批处理作业的配置的子上下文。
When writing integration tests that rely on a loaded Spring ApplicationContext
, it is
often sufficient to test against a single context. However, there are times when it is
beneficial or even necessary to test against a hierarchy of ApplicationContext
instances. For example, if you are developing a Spring MVC web application, you typically
have a root WebApplicationContext
loaded by Spring’s ContextLoaderListener
and a
child WebApplicationContext
loaded by Spring’s DispatcherServlet
. This results in a
parent-child context hierarchy where shared components and infrastructure configuration
are declared in the root context and consumed in the child context by web-specific
components. Another use case can be found in Spring Batch applications, where you often
have a parent context that provides configuration for shared batch infrastructure and a
child context for the configuration of a specific batch job.
可以通过使用 @ContextHierarchy
注解在单个测试类或测试类层次结构中声明上下文配置来编写使用上下文层次结构的集成测试。如果在测试类层次结构中的多个类上声明上下文层次结构,则还可以合并或覆盖上下文层次结构中特定命名级别的上下文配置。在合并层次结构中给定级别的配置时,配置资源类型(即 XML 配置文件或组件类)必须一致。否则,完全可以接受使用不同的资源类型配置上下文层次结构中的不同级别。
You can write integration tests that use context hierarchies by declaring context
configuration with the @ContextHierarchy
annotation, either on an individual test class
or within a test class hierarchy. If a context hierarchy is declared on multiple classes
within a test class hierarchy, you can also merge or override the context configuration
for a specific, named level in the context hierarchy. When merging configuration for a
given level in the hierarchy, the configuration resource type (that is, XML configuration
files or component classes) must be consistent. Otherwise, it is perfectly acceptable to
have different levels in a context hierarchy configured using different resource types.
本节中其余基于 JUnit Jupiter 的示例展示了需要使用上下文层次结构的集成测试的常见配置场景。
The remaining JUnit Jupiter based examples in this section show common configuration scenarios for integration tests that require the use of context hierarchies.
带有上下文层次结构的单个测试类
Single test class with context hierarchy
ControllerIntegrationTests
表示 Spring MVC Web 应用程序的典型集成测试场景,它声明一个由两个级别组成的上下文层次结构,它一个用于根 WebApplicationContext
(通过使用 TestAppConfig
@Configuration
类加载),另一个用于分发器 servlet WebApplicationContext
(通过使用 WebConfig
@Configuration
类加载)。自动注入测试实例的 WebApplicationContext
是子上下文的一个(即层次结构中最低的上下文)。以下清单显示了此配置场景:
ControllerIntegrationTests
represents a typical integration testing scenario for a
Spring MVC web application by declaring a context hierarchy that consists of two levels,
one for the root WebApplicationContext
(loaded by using the TestAppConfig
@Configuration
class) and one for the dispatcher servlet WebApplicationContext
(loaded by using the WebConfig
@Configuration
class). The WebApplicationContext
that is autowired into the test instance is the one for the child context (that is, the
lowest context in the hierarchy). The following listing shows this configuration scenario:
-
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
// ...
}
带有隐式父上下文的类层次结构
Class hierarchy with implicit parent context
此示例中的测试类在测试类层次结构中定义了上下文层次结构。AbstractWebTests
声明 Spring 支持的 Web 应用程序中根 WebApplicationContext
的配置。不过,请注意,AbstractWebTests
不声明 @ContextHierarchy
。因此,AbstractWebTests
的子类可以选择参与上下文层次结构或遵循 @ContextConfiguration
的标准语义。SoapWebServiceTests
和 RestWebServiceTests
都通过使用 @ContextHierarchy
扩展 AbstractWebTests
并定义上下文层次结构。结果是加载了三个应用程序上下文(一个用于每个 @ContextConfiguration
声明),并且基于 AbstractWebTests
中的配置加载的应用程序上下文被设置为为具体子类加载的每个上下文的父上下文。以下清单显示了此配置场景:
The test classes in this example define a context hierarchy within a test class
hierarchy. AbstractWebTests
declares the configuration for a root
WebApplicationContext
in a Spring-powered web application. Note, however, that
AbstractWebTests
does not declare @ContextHierarchy
. Consequently, subclasses of
AbstractWebTests
can optionally participate in a context hierarchy or follow the
standard semantics for @ContextConfiguration
. SoapWebServiceTests
and
RestWebServiceTests
both extend AbstractWebTests
and define a context hierarchy by
using @ContextHierarchy
. The result is that three application contexts are loaded (one
for each declaration of @ContextConfiguration
), and the application context loaded
based on the configuration in AbstractWebTests
is set as the parent context for each of
the contexts loaded for the concrete subclasses. The following listing shows this
configuration scenario:
-
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()
带有合并上下文层次结构配置的类层次结构
Class hierarchy with merged context hierarchy configuration
此示例中的类展示了如何使用命名的层次结构级别来合并上下文层次结构中特定级别的配置。BaseTests
在层次结构中定义两个级别,即 parent
和 child
。ExtendedTests
扩展了 BaseTests
并指示 Spring TestContext 框架合并 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"}
加载的上下文的父上下文。以下清单显示了此配置场景:
The classes in this example show the use of named hierarchy levels in order to merge the
configuration for specific levels in a context hierarchy. BaseTests
defines two levels
in the hierarchy, parent
and child
. ExtendedTests
extends BaseTests
and instructs
the Spring TestContext Framework to merge the context configuration for the child
hierarchy level, by ensuring that the names declared in the name
attribute in
@ContextConfiguration
are both child
. The result is that three application contexts
are loaded: one for /app-config.xml
, one for /user-config.xml
, and one for
{"/user-config.xml", "/order-config.xml"}
. As with the previous example, the
application context loaded from /app-config.xml
is set as the parent context for the
contexts loaded from /user-config.xml
and {"/user-config.xml", "/order-config.xml"}
.
The following listing shows this configuration scenario:
-
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() {}
带有覆盖上下文层次结构配置的类层次结构
Class hierarchy with overridden context hierarchy configuration
与前一个示例相反,此示例演示了如何通过将 @ContextConfiguration
中的 inheritLocations
标志设置为 false
来覆盖上下文层次结构中给定命名级别的配置。因此,ExtendedTests
的应用程序上下文仅从 /test-user-config.xml
加载,并将其父级设置为从 /app-config.xml
加载的上下文。以下清单显示了此配置场景:
In contrast to the previous example, this example demonstrates how to override the
configuration for a given named level in a context hierarchy by setting the
inheritLocations
flag in @ContextConfiguration
to false
. Consequently, the
application context for ExtendedTests
is loaded only from /test-user-config.xml
and
has its parent set to the context loaded from /app-config.xml
. The following listing
shows this configuration scenario:
-
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() {}
Dirtying a context within a context hierarchy
如果您在上下文中配置为上下级关系的一部分的测试中使用 |
Dirtying a context within a context hierarchy
If you use |