此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Framework 6.2.6spring-doc.cadn.net.cn

上下文层次结构

当编写依赖于加载的 Spring 的集成测试时ApplicationContext是的 通常足以针对单个上下文进行测试。但是,有时确实如此 对于针对ApplicationContext实例。例如,如果您正在开发 Spring MVC Web 应用程序,则通常 有一个根WebApplicationContext由 Spring 的ContextLoaderListener以及 孩子WebApplicationContext由 Spring 的DispatcherServlet.这会导致 父子上下文层次结构,其中共享组件和基础设施配置 在根上下文中声明,并在子上下文中由 Web 特定的 组件。另一个用例可以在 Spring Batch 应用程序中找到,您经常在其中 具有为共享批处理基础架构提供配置的父上下文,以及 子上下文,用于特定批处理作业的配置。spring-doc.cadn.net.cn

您可以通过声明 context 来编写使用上下文层次结构的集成测试 配置与@ContextHierarchy注解,或者在单个测试类上 或在测试类层次结构中。如果在多个类上声明了上下文层次结构 在 Test Class 层次结构中,您还可以合并或覆盖 Context Configuration 对于上下文层次结构中的特定命名级别。合并 层次结构中的给定级别,则配置资源类型(即 XML 配置 文件或组件类)必须一致。否则,完全可以接受 在使用不同的资源类型配置的上下文层次结构中具有不同的级别。spring-doc.cadn.net.cn

如果您使用@DirtiesContext在其 context 配置为 context 一部分的测试中 层次结构中,您可以使用hierarchyMode标志来控制上下文缓存的 清除。spring-doc.cadn.net.cn

有关更多详细信息,请参阅@DirtiesContextSpring Testing Annotations@DirtiesContextjavadoc 的 Java 文档。spring-doc.cadn.net.cn

本节中基于 JUnit Jupiter 的示例显示了以下常见配置场景: 需要使用上下文层次结构的集成测试。spring-doc.cadn.net.cn

具有上下文层次结构的单个测试类spring-doc.cadn.net.cn

ControllerIntegrationTests表示 Spring MVC Web 应用程序,通过声明一个由两个级别组成的上下文层次结构, 一个用于根WebApplicationContext(使用TestAppConfig @Configuration类)和一个用于 Dispatcher Servlet 的WebApplicationContext(使用WebConfig @Configuration类)。这WebApplicationContext)是子上下文的 (即 层次结构中最低的上下文)。下面的清单显示了此配置场景:spring-doc.cadn.net.cn

@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

	// ...
}

具有隐式父上下文的类层次结构spring-doc.cadn.net.cn

此示例中的测试类定义测试类中的上下文层次结构 等级制度。AbstractWebTests声明根的配置WebApplicationContext在 Spring 支持的 Web 应用程序中。但请注意,AbstractWebTests不声明@ContextHierarchy.因此,的子类AbstractWebTests可以选择参与上下文层次结构或遵循 的标准语义@ContextConfiguration.SoapWebServiceTestsRestWebServiceTests两者都扩展AbstractWebTests并通过以下方式定义上下文层次结构 用@ContextHierarchy.结果是加载了三个应用程序上下文(一个 对于每个声明@ContextConfiguration) 并加载应用程序上下文 根据AbstractWebTests设置为每个 为 Concrete 子类加载的上下文。下面的清单显示了这一点 配置场景:spring-doc.cadn.net.cn

@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()

具有合并上下文层次结构配置的类层次结构spring-doc.cadn.net.cn

此示例中的类演示了命名层次结构级别的使用,以便将 context 层次结构中特定级别的配置。BaseTests定义两个级别 在层次结构中,parentchild.ExtendedTests延伸BaseTests并指示 Spring TestContext 框架来合并child层次结构级别,方法是确保name属性@ContextConfiguration都是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"}. 下面的清单显示了此配置场景:spring-doc.cadn.net.cn

@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() {}

具有覆盖上下文层次结构配置的类层次结构spring-doc.cadn.net.cn

与前面的示例相比,此示例演示了如何覆盖 配置,方法是将inheritLocations标志输入@ContextConfigurationfalse.因此, 的应用程序上下文ExtendedTests仅从/test-user-config.xml和 将其父项设置为从中加载的上下文/app-config.xml.以下清单 显示了此配置方案:spring-doc.cadn.net.cn

@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() {}

具有 Bean 覆盖的上下文层次结构spring-doc.cadn.net.cn

什么时候@ContextHierarchyBean 覆盖结合使用,例如@TestBean,@MockitoBean@MockitoSpyBean,这可能是可取的或必要的 将覆盖应用于上下文层次结构中的单个级别。为了实现这一目标, Bean 覆盖必须指定一个上下文名称,该名称与通过name属性@ContextConfiguration.spring-doc.cadn.net.cn

以下测试类将第二个层次结构级别的名称配置为"user-config",并同时指定UserService应该包裹在 一个 Mockito 间谍,在名为"user-config".因此,Spring 将仅 尝试在"user-config"上下文,并且不会尝试创建 父上下文中的 spy。spring-doc.cadn.net.cn

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
	@ContextConfiguration(classes = AppConfig.class),
	@ContextConfiguration(classes = UserConfig.class, name = "user-config")
})
class IntegrationTests {

	@MockitoSpyBean(contextName = "user-config")
	UserService userService;

	// ...
}
@ExtendWith(SpringExtension::class)
@ContextHierarchy(
	ContextConfiguration(classes = [AppConfig::class]),
	ContextConfiguration(classes = [UserConfig::class], name = "user-config"))
class IntegrationTests {

	@MockitoSpyBean(contextName = "user-config")
	lateinit var userService: UserService

	// ...
}

在上下文层次结构的不同级别中应用 Bean 覆盖时,你可能需要 将所有 bean 覆盖实例注入到测试类中,以便 与它们交互 — 例如,为 mock 配置 stubing。然而@Autowired将始终注入在 Context 层次结构的最低级别中找到的匹配 bean。 因此,要从上下文层次结构中的特定级别注入 bean 覆盖实例, 您需要使用适当的 bean 覆盖注释来注释字段,并配置 上下文级别的名称。spring-doc.cadn.net.cn

以下测试类将层次结构级别的名称配置为"parent""child".它还声明了两个PropertyService字段,这些字段配置为 create 或 replacePropertyServicebeans 替换为 Mockito mocks, 叫"parent""child".因此,来自"parent"context 将 注入到propertyServiceInParent字段,以及来自"child"context 将被注入到propertyServiceInChild田。spring-doc.cadn.net.cn

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
	@ContextConfiguration(classes = ParentConfig.class, name = "parent"),
	@ContextConfiguration(classes = ChildConfig.class, name = "child")
})
class IntegrationTests {

	@MockitoBean(contextName = "parent")
	PropertyService propertyServiceInParent;

	@MockitoBean(contextName = "child")
	PropertyService propertyServiceInChild;

	// ...
}
@ExtendWith(SpringExtension::class)
@ContextHierarchy(
	ContextConfiguration(classes = [ParentConfig::class], name = "parent"),
	ContextConfiguration(classes = [ChildConfig::class], name = "child"))
class IntegrationTests {

	@MockitoBean(contextName = "parent")
	lateinit var propertyServiceInParent: PropertyService

	@MockitoBean(contextName = "child")
	lateinit var propertyServiceInChild: PropertyService

	// ...
}