对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

上下文缓存

一旦TestContext框架为测试加载了ApplicationContext(或WebApplicationContext),该上下文将被缓存并在同一测试套件中所有声明相同唯一上下文配置的后续测试中重用。要理解缓存的工作原理,重要的是要理解“唯一”和“测试套件”的含义。spring-doc.cadn.net.cn

一个 ApplicationContext 可以通过用于加载它的配置参数组合唯一标识。因此,唯一的配置参数组合用于生成上下文缓存的键。TestContext 框架使用以下配置参数来构建上下文缓存键:spring-doc.cadn.net.cn

例如,如果TestClassA 指定了 {"app-config.xml", "test-config.xml"} 用于 locations(或 value)属性的 @ContextConfiguration,TestContext 框架将加载相应的 ApplicationContext 并将其存储在基于这些位置的键的 static 上下文缓存中。因此,如果 TestClassB 还为它的位置定义了 {"app-config.xml", "test-config.xml"}(无论是显式还是通过继承隐式地),但没有定义 @WebAppConfiguration,则不同的 ContextLoader、不同的活动配置文件、不同的上下文初始化器、不同的测试属性源或不同的父上下文,则两个测试类共享相同的 ApplicationContext。这意味着加载应用程序上下文的设置成本仅在一次(每个测试套件)中发生,并且后续的测试执行速度要快得多。spring-doc.cadn.net.cn

测试套件和分离进程

Spring TestContext框架将应用程序上下文存储在静态缓存中。这意味着上下文实际上是存储在一个static变量中。换句话说,如果测试在单独的进程中运行,静态缓存会在每次测试执行之间被清除,这实际上禁用了缓存机制。spring-doc.cadn.net.cn

要从缓存机制中受益,所有测试必须在同一进程或测试套件中运行。这可以通过在IDE中将所有测试作为一个组执行来实现。同样,在使用构建框架(如Ant、Maven或Gradle)执行测试时,确保构建框架在测试之间不进行fork非常重要。例如,如果Maven Surefire插件的 forkMode 设置为alwayspertest,TestContext框架无法在测试类之间缓存应用程序上下文,结果构建过程会显著变慢。spring-doc.cadn.net.cn

上下文缓存的大小是有限制的,默认的最大大小为32。每当达到最大大小时,将使用最近最少使用(LRU)策略来驱逐和关闭过期的上下文。您可以通过设置名为spring.test.context.cache.maxSize的JVM系统属性从命令行或构建脚本中配置最大大小。作为替代方案,您也可以通过SpringProperties机制设置相同的属性。spring-doc.cadn.net.cn

由于在一个给定的测试套件中加载大量的应用程序上下文可能会导致套件运行时间过长,因此通常有益于知道已加载和缓存了多少个上下文。要查看底层上下文缓存的统计信息,可以将org.springframework.test.context.cache日志类别设置为DEBUGspring-doc.cadn.net.cn

在测试破坏应用程序上下文并需要重新加载的情况下(例如,通过修改 bean 定义或应用程序对象的状态),您可以使用 @DirtiesContext 注解您的测试类或测试方法(参见 Spring 测试注解 中对 @DirtiesContext 的讨论)。这会指示 Spring 从缓存中删除上下文,并在运行下一个需要相同应用程序上下文的测试之前重新构建应用程序上下文。请注意,@DirtiesContext 注解的支持由 DirtiesContextBeforeModesTestExecutionListenerDirtiesContextTestExecutionListener 提供,默认情况下这些功能已启用。spring-doc.cadn.net.cn

ApplicationContext生命周期和控制台日志记录

当您需要调试使用 Spring TestContext Framework 执行的测试时,分析控制台输出(即输出到 SYSOUTSYSERR 流的输出)可能会很有帮助。一些构建工具和 IDE 可以将控制台输出与特定测试关联;然而,一些控制台输出无法轻松与特定测试关联。spring-doc.cadn.net.cn

关于由Spring框架本身或在ApplicationContext中注册的组件触发的控制台日志,了解在测试套件中由Spring TestContext框架加载的ApplicationContext的生命周期非常重要。spring-doc.cadn.net.cn

ApplicationContext 在测试中通常在测试类的实例被准备时加载 — 例如,为了将依赖项注入到测试实例的 @Autowired 字段中。这意味着在 ApplicationContext 初始化期间触发的任何控制台日志通常无法与单个测试方法相关联。然而,如果根据 @DirtiesContext 语义在测试方法执行前立即关闭上下文,则会在测试方法执行前加载一个新的上下文实例。在后一种情况下,IDE 或构建工具可能会将控制台日志与单个测试方法相关联。spring-doc.cadn.net.cn

可以通过以下任一情况关闭测试的 ApplicationContextspring-doc.cadn.net.cn

如果在特定测试方法之后根据 @DirtiesContext 语义关闭上下文,IDE 或构建工具可能会将控制台日志与单个测试方法相关联。如果在测试类之后根据 @DirtiesContext 语义关闭上下文,则在 ApplicationContext 关闭期间触发的任何控制台日志都无法与单个测试方法相关联。同样,通过 JVM 关闭钩子在关闭阶段触发的任何控制台日志也无法与单个测试方法相关联。spring-doc.cadn.net.cn

当通过JVM关闭钩子关闭Spring ApplicationContext时,关闭阶段执行的回调是在名为SpringContextShutdownHook的线程上执行的。因此,如果您希望在通过JVM关闭钩子关闭ApplicationContext时禁用控制台日志记录,您可以向日志框架注册一个自定义过滤器,以忽略由该线程发起的任何日志记录。spring-doc.cadn.net.cn