Attend this talk to learn about the latest and greatest in the world of testing using the Spring Framework and JUnit Jupiter (a.k.a. JUnit 5) including tips for testing with Spring AOT and GraalVM native images.
are currently under development. • This overview of new technology represents no commitment from VMware to deliver these features in any generally available product. • Features are subject to change, and must not be included in contracts, purchase orders, or sales agreements of any kind. • Technical feasibility and market demand will affect final delivery. • Pricing and packaging for any new features/functionality/technology discussed or presented, have not been determined. • The information in this presentation is for informational purposes only and may not be incorporated into any contract. There is no commitment or obligation to deliver any items presented herein. Disclaimer
Reporting format • https://github.com/ota4j-team/open-test-reporting • New IterationSelector • for selecting a subset of a test’s or container’s iterations • Various improvements to ConsoleLauncher • --single-color and --color-palette • --list-engines • JUnit Platform Suite Engine included in stand-alone JAR
• ALWAYS, ON_SUCCESS, NEVER • New TestInstancePreConstructCallback extension API • counterpart to existing TestInstancePreDestroyCallback • Reusable parameter resolution for method invocations • via ExecutableInvoker API • accessed via ExtensionContext • used for @MethodSource factory methods • @MethodSource factory methods can accept arguments • resolved by ParameterResolver extensions • new syntax to disambiguate local factory methods
• INFERRED, SAME_THREAD, SEPARATE_THREAD • @EnabledOnOs and @DisabledOnOs • support for OS architectures • support for FreeBSD and OpenBSD • @EnabledInNativeImage and @DisabledInNativeImage • enable/disable tests in GraalVM native image • AssertionFailureBuilder • reuse Jupiter’s logic for creating failure messages
to stable • Stacktrace pruning to hide internal JUnit calls • ConsoleLauncher • new testfeed details mode • new discover subcommand for test discovery without execution • Dry-run mode for test execution • New LauncherInterceptor SPI • New NamespacedHierarchicalStore for use in third-party test engines
explicit ClassLoader • ReflectionSupport.findMethod(Class<?>, String, String) • now uses ClassLoader of the supplied class to load parameter types • used by DiscoverySelectors.selectMethod(Class<?>, String, String) • DiscoverySelectors methods for ClassSelector, NestedClassSelector, MethodSelector, and NestedMethodSelector that accept an explicit ClassLoader
to stable • Failure threshold for @RepeatedTest • New TempDirFactory SPI for customizing @TempDir • Custom ClassLoader support for @EnabledIf, @DisabledIf, @MethodSource, and @ParameterizedTest argument conversion • Improved configurability of parallel execution • AnnotationBasedArgumentsProvider/AnnotationBasedArgumentConverter • base classes for implementing ArgumentsProvider and ArgumentConverter
@Suite engine • Extension API for customizing the ClassLoader in Jupiter • @FieldSource for parameterized tests • @ContainerTemplate • analagous to @TestTemplate • ContainerTemplateInvocationContextProvider extension API • @ParameterizedContainer • effectively parameterized test classes
• useful for patched test modules with Maven • Servlet API 6.0 baseline in Servlet mocks and MockMvc • with Servlet 5.0 compatibility at runtime • Assertions against Cookie attributes in CookieResultMatchers for MockMvc • Default TestExecutionListeners enabled in JUnit 4 and TestNG base test classes • Revised logging in the TestContext framework (TCF) • ApplicationContextFailureProcessor SPI for processing ApplicationContext failures in the TCF • used by Spring Boot • Ahead of Time and GraalVM native image support
• record events from threads other than main test thread • assert events from separate thread – for example with Awaitility • limitations in JUnit Jupiter • Support for null in MockHttpServletResponse.setCharacterEncoding() • New MockHttpServletRequestBuilder.setRemoteAddress() method • Avoid repeated attempts to load failing ApplicationContext in the TestContext framework • Potential integration with @ParameterizedContainer in JUnit Jupiter 5.11
• part of the build process • utilized at runtime • GraalVM – https://www.graalvm.org/ • polyglot programming on the JVM • native image • compiling JVM applications to OS-specific binaries • closed world assumptions • no classpath • requires runtime hints
to inspect an ApplicationContext at build time and apply decisions and discovery logic that usually happens at runtime. • Core infrastructure in Spring Framework • Implemented across the portfolio • Build tools in Spring Boot • Spring AOT optimizations are used in GraalVM native image
Build-time detection of Spring integration tests • JUnit Jupiter, JUnit 4, and implicit support for TestNG etc. • Build-time AOT processing ◦ each unique test ApplicationContext will be refreshed for AOT processing • Runtime AOT support ◦ Spring integration tests use AOT-optimized ApplicationContexts
Labs, Spring, and Micronaut • Build native image • Run tests in native image using the JUnit Platform • Plugins for Gradle and Maven ◦ incorporated in Spring Boot build plugins
TestRuntimeHintsRegistrar • register globally via META-INF/spring/aot.factories • RuntimeHintsRegistrar • register globally via META-INF/spring/aot.factories • register locally on a test class via @ImportRuntimeHints • Annotate test class with @Reflective or @RegisterReflectionForBinding
AOT build-time processing • AOT runtime execution support • Spring Framework and Spring Boot context loaders implement AotContextLoader • TestExecutionListener: implement AotTestExecutionListener • to participate in AOT processing • See SqlScriptsTestExecutionListener for an example
JUnit Jupiter execution conditions • Native Build Tools (NBT) support for JUnit Platform • Explicit support for JUnit Jupiter and JUnit 4 • Spring Boot 3 build tools ◦ Gradle and Maven ◦ Integration with NBT for testing support
./mvnw -PnativeTest test • Gradle ◦ ./gradlew nativeTest • Definitely do this before deploying a native image to production • But this can take a considerable amount of time • So you won’t do this multiple times a day • Consider running tests in AOT mode on the JVM first
ready for prime time ◦ in terms of developer experience (DX) ◦ requires manual setup • But still possible with both Maven and Gradle ◦ Today I’ll show you how with Maven • Can be useful to: ◦ run tests in AOT mode on the JVM before running within a native image ◦ debug failing tests first in AOT mode on the JVM
sources ◦ ./mvnw clean test spring-boot:process-test-aot • Run tests in AOT mode on JVM ◦ ./mvnw -Dspring.aot.enabled=true test • Add generated sources as “test” source folder in IDE ◦ target/spring-aot/test/sources/ ◦ output directory can be same as for your test code • Add CGLIB compiled classes to output classpath in IDE • alternative: @Configuration(proxyBeanMethods = false)
• That’s it! • You should see log output like: • Loading ApplicationContext for AOT runtime for test class springio.service.ServiceTests • Starting AOT-processed ServiceTests
to AOT-optimized ApplicationContext ◦ org.springframework.test.context.aot.AotTestContextInitializers__Generated ◦ For example, ServiceTests__TestContext001_ApplicationContextInitializer • Set breakpoint in ApplicationContextInitializer • Debug test class with -Dspring.aot.enabled=true