提前支持测试
本章介绍了Spring对集成测试的“提前编译(Ahead of Time, AOT)”支持,该支持是借助Spring TestContext框架来实现的。
测试支持通过对Spring的核心AOT支持进行扩展,增加了以下功能。
-
在构建时检测当前项目中所有使用TestContext框架加载ApplicationContext的集成测试。
-
明确支持基于JUnit Jupiter和JUnit 4的测试类,同时隐式支持TestNG以及其他使用Spring核心测试注解的测试框架——只要这些测试是使用为当前项目注册的JUnit Platform TestEngine来运行的。
-
构建时AOT处理:当前项目中的每个唯一的测试ApplicationContext都将进行AOT处理刷新。
-
运行时AOT支持:在AOT运行模式下执行时,Spring集成测试将使用经过AOT优化过的ApplicationContext,该ApplicationContext会与上下文缓存透明地协同工作。
默认情况下,所有测试都在AOT模式下启用。然而,你可以通过使用@DisabledInAotMode注解来选择性地禁用整个测试类或单个测试方法在AOT模式下的执行。当使用JUnit Jupiter时,你可以通过Jupiter的@EnabledInNativeImage和@DisabledInNativeImage注解来选择性地启用或禁用GraalVM原生镜像中的测试。需要注意的是,@DisabledInAotMode在GraalVM原生镜像运行时也会禁用被标注的测试类或测试方法,这与JUnit Jupiter的@DisabledInNativeImage注解的作用类似。
默认情况下,如果在构建时的AOT处理过程中遇到错误,将会抛出异常,整个构建过程会立即失败。
如果你希望在遇到错误后仍继续进行构建时的AOT处理,可以禁用failOnError模式。这样,错误将以WARN级别被记录;如果希望记录更详细的错误信息,则可以将其设置为DEBUG级别。
可以通过命令行或构建脚本来禁用failOnError模式,方法是将名为spring.test.aot.processing.failOnError的JVM系统属性设置为false。或者,也可以通过SpringProperties机制来设置该属性。
在AOT模式下,不能使用JPA的@PersistenceContext和@PersistenceUnit注解来在测试类中执行依赖注入。
不过,从Spring Framework 7.0开始,你可以使用@Autowired分别注入EntityManager或EntityManagerFactory到测试类中,而不是使用@PersistenceContext和@PersistenceUnit。
在AOT模式下,不支持@ContextHierarchy注解。
为了在GraalVM原生镜像中提供特定于测试的运行时提示,您有以下选项。
-
实现一个自定义的 TestRuntimeHintsRegistrar,并通过
META-INF/spring/aot.factories在全局范围内进行注册。 -
实现一个自定义的 [RuntimeHintsRegistrar](https://docs.spring.io/spring-framework/docs/7.0.3/javadoc-api/org/springframework/aot/hint RuntimeHintsRegistrar.html),通过
META-INF/spring/aot.factories在全局范围内进行注册,或者通过 @ImportRuntimeHints 在测试类上局部注册。 -
使用 @Reflective 或 @RegisterReflectionForBinding 注解测试类。
-
有关 Spring 核心运行时提示和注解支持的详细信息,请参阅 运行时提示。
TestRuntimeHintsRegistrar API 是核心 RuntimeHintsRegistrar API 的补充。如果您需要为测试支持注册不特定于某个测试类的全局提示,建议实现 RuntimeHintsRegistrar 而不是使用针对特定测试的 API。
如果你实现了一个自定义的ContextLoader,它必须实现AotContextLoader,以便提供AOT构建时处理和AOT运行时执行支持。不过请注意,Spring Framework和Spring Boot提供的所有上下文加载器实现都已经实现了AotContextLoader。
如果你实现了一个自定义的TestExecutionListener,它必须实现AotTestExecutionListener,才能参与AOT处理。可以参考spring-test模块中的SqlScriptsTestExecutionListener作为示例。