上下文管理
每个 TestContext
为其负责的测试实例提供上下文管理和缓存支持。测试实例不会自动获得对已配置的 ApplicationContext
的访问权限。然而,如果测试类实现了 ApplicationContextAware
接口,ApplicationContext
的引用将被提供给测试实例。请注意,AbstractJUnit4SpringContextTests
和 AbstractTestNGSpringContextTests
实现了 ApplicationContextAware
接口,因此会自动提供对 ApplicationContext
的访问权限。
@Autowired ApplicationContext
作为实现 ApplicationContextAware
接口的替代方案,你可以通过在字段或 setter 方法上使用 @Autowired
注解来为你的测试类注入应用上下文,如下例所示:
- Java
- Kotlin
@SpringJUnitConfig
class MyTest {
@Autowired 1
ApplicationContext applicationContext;
// class body...
}
注入
ApplicationContext
。
@SpringJUnitConfig
class MyTest {
@Autowired 1
lateinit var applicationContext: ApplicationContext
// class body...
}
注入
ApplicationContext
。
类似地,如果你的测试配置为加载 WebApplicationContext
,你可以将 web 应用上下文注入到你的测试中,如下所示:
- Java
- Kotlin
@SpringJUnitWebConfig 1
class MyWebAppTest {
@Autowired 2
WebApplicationContext wac;
// class body...
}
配置
WebApplicationContext
。注入
WebApplicationContext
。
@SpringJUnitWebConfig 1
class MyWebAppTest {
@Autowired 2
lateinit var wac: WebApplicationContext
// class body...
}
配置
WebApplicationContext
。注入
WebApplicationContext
。
通过 @Autowired
进行的依赖注入由 DependencyInjectionTestExecutionListener
提供,该监听器默认已配置(参见 测试夹具的依赖注入)。
使用 TestContext 框架的测试类不需要扩展任何特定的类或实现特定的接口来配置其应用程序上下文。相反,配置是通过在类级别声明 @ContextConfiguration
注解来实现的。如果你的测试类没有显式声明应用程序上下文资源位置或组件类,配置的 ContextLoader
将决定如何从默认位置或默认配置类加载上下文。除了上下文资源位置和组件类外,应用程序上下文还可以通过应用程序上下文初始化器进行配置。
以下部分解释了如何使用 Spring 的 @ContextConfiguration
注解通过 XML 配置文件、Groovy 脚本、组件类(通常是 @Configuration
类)或上下文初始化器来配置测试的 ApplicationContext
。或者,你也可以为实现和配置自己的自定义 SmartContextLoader
以应对高级用例。
章节摘要
📄️ 使用 XML 资源进行上下文配置
要通过使用 XML 配置文件为你的测试加载 ApplicationContext,请使用 @ContextConfiguration 注解你的测试类,并通过一个包含 XML 配置元数据资源位置的数组来配置 locations 属性。一个普通或相对路径(例如 context.xml)被视为相对于定义测试类的包路径的类路径资源。以斜杠开头的路径被视为绝对类路径位置(例如 /org/example/config.xml)。表示资源 URL 的路径(即带有 classpath:、file:、http: 等前缀的路径)将按原样使用。
📄️ 使用 Groovy 脚本进行上下文配置
要使用 Groovy 脚本(使用 Groovy Bean 定义 DSL)为你的测试加载 ApplicationContext,你可以使用 @ContextConfiguration 注解来标注你的测试类,并通过配置 locations 或 value 属性来指定包含 Groovy 脚本资源位置的数组。Groovy 脚本的资源查找语义与 XML 配置文件中描述的相同。
📄️ 使用组件类进行上下文配置
要通过使用组件类(参见基于 Java 的容器配置)为测试加载 ApplicationContext,你可以使用 @ContextConfiguration 注解你的测试类,并通过包含组件类引用的数组配置 classes 属性。以下示例展示了如何做到这一点:
📄️ 混合使用 XML、Groovy 脚本和组件类
有时候,可能会希望混合使用 XML 配置文件、Groovy 脚本和组件类(通常是 @Configuration 类)来为测试配置 ApplicationContext。例如,如果在生产环境中使用 XML 配置,你可能决定在测试中使用 @Configuration 类来配置特定的 Spring 管理的组件,反之亦然。
📄️ 配置 使用上下文自定义器进行配置
ContextCustomizer 负责在将 bean 定义加载到上下文之后、但在上下文刷新之前,对提供的 ConfigurableApplicationContext 进行自定义。
📄️ 使用上下文初始化器进行上下文配置
要通过使用上下文初始化器为你的测试配置一个 ApplicationContext,请使用 @ContextConfiguration 注解你的测试类,并通过配置 initializers 属性来引用实现 ApplicationContextInitializer 的类数组。然后,声明的上下文初始化器将用于初始化为你的测试加载的 ConfigurableApplicationContext。请注意,每个声明的初始化器支持的具体 ConfigurableApplicationContext 类型必须与当前使用的 SmartContextLoader 创建的 ApplicationContext 类型兼容(通常是 GenericApplicationContext)。此外,初始化器的调用顺序取决于它们是否实现了 Spring 的 Ordered 接口,或者是否使用了 Spring 的 @Order 注解或标准的 @Priority 注解。以下示例展示了如何使用初始化器:
📄️ 上下文配置继承
@ContextConfiguration 支持布尔类型的 inheritLocations 和 inheritInitializers 属性,用于指示是否应继承由超类声明的资源位置或组件类以及上下文初始化器。这两个标志的默认值均为 true。这意味着测试类会继承由任何超类声明的资源位置或组件类以及上下文初始化器。具体来说,测试类的资源位置或组件类会被追加到由超类声明的资源位置或注解类列表中。同样,给定测试类的初始化器也会被添加到由测试超类定义的初始化器集合中。因此,子类可以选择扩展资源位置、组件类或上下文初始化器。
📄️ 使用环境配置文件进行上下文配置
Spring 框架对环境和配置文件(也称为“bean 定义配置文件”)提供了顶级支持,并且可以配置集成测试以激活特定的 bean 定义配置文件,以应对各种测试场景。这是通过在测试类上使用 @ActiveProfiles 注解并提供一个配置文件列表来实现的,这些配置文件在加载测试的 ApplicationContext 时会被激活。
📄️ 使用测试属性源的上下文配置
Spring 框架对具有属性源层次结构的环境概念提供了顶级支持,并且你可以为集成测试配置特定于测试的属性源。与在 @Configuration 类上使用的 @PropertySource 注解不同,你可以在测试类上声明 @TestPropertySource 注解,以声明测试属性文件的资源位置或内联属性。这些测试属性源会被添加到为注解的集成测试加载的 ApplicationContext 的 Environment 中的 PropertySources 集合中。
📄️ 使用动态属性源的上下文配置
Spring TestContext 框架通过 DynamicPropertyRegistry、@DynamicPropertySource 注解和 DynamicPropertyRegistrar API 提供了对动态属性的支持。
📄️ 加载 WebApplicationContext
要指示 TestContext 框架加载 WebApplicationContext 而不是标准的 ApplicationContext,你可以在相应的测试类上使用 @WebAppConfiguration 注解。
📄️ 使用 Web Mocks
为了提供全面的 Web 测试支持,TestContext 框架默认启用了 ServletTestExecutionListener。当针对 WebApplicationContext 进行测试时,该 TestExecutionListener 会在每个测试方法执行之前,使用 Spring Web 的 RequestContextHolder 设置默认的线程本地状态,并根据 @WebAppConfiguration 配置的基础资源路径创建 MockHttpServletRequest、MockHttpServletResponse 和 ServletWebRequest。ServletTestExecutionListener 还确保 MockHttpServletResponse 和 ServletWebRequest 可以被注入到测试实例中,并且在测试完成后清理线程本地状态。
📄️ 上下文缓存
一旦 TestContext 框架为测试加载了一个 ApplicationContext(或 WebApplicationContext),该上下文将被缓存,并在同一测试套件中所有声明相同唯一上下文配置的后续测试中重复使用。要理解缓存的工作原理,重要的是要理解“唯一”和“测试套件”的含义。
📄️ 上下文故障阈值
自 Spring Framework 6.1 起,引入了一种上下文失败阈值策略,该策略有助于避免重复尝试加载失败的 ApplicationContext。默认情况下,失败阈值设置为 1,这意味着对于给定的上下文缓存键(参见 \[Context Caching]\(Context Caching)),只会尝试加载一次 ApplicationContext。任何后续尝试为相同的上下文缓存键加载 ApplicationContext 的操作都会立即抛出一个 IllegalStateException,并附带一条错误信息,解释该尝试已被预先跳过。这种行为通过避免重复尝试加载永远不会成功加载的 ApplicationContext,使得单个测试类和测试套件能够更快地失败——例如,由于配置错误或缺少阻止上下文在当前环境中加载的外部资源。
📄️ 上下文层次结构
在编写依赖于已加载的 Spring ApplicationContext 的集成测试时,通常针对单个上下文进行测试就足够了。然而,有时针对 ApplicationContext 实例的层次结构进行测试是有益的,甚至是必要的。例如,如果你正在开发一个 Spring MVC Web 应用程序,通常会有一个由 Spring 的 ContextLoaderListener 加载的根 WebApplicationContext,以及一个由 Spring 的 DispatcherServlet 加载的子 WebApplicationContext。这将导致一个父子上下文层次结构,其中共享组件和基础设施配置在根上下文中声明,并由特定于 Web 的组件在子上下文中使用。另一个用例可以在 Spring Batch 应用程序中找到,其中通常会有一个父上下文为共享的批处理基础设施提供配置,而子上下文则为特定批处理作业的配置提供服务。