Sam Brannen
@sam_brannen
Spring I/O 2022
Testing with
and
Copyright © 2022 VMware, Inc. or its affiliates.
JUnit
©2020 VMware, Inc. 2
This presentation may contain product features or functionality that 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
Sam Brannen
● Staff Software Engineer
● Java Developer for over 20 years
● Spring Framework Core Committer since 2007
● JUnit 5 Core Committer since October 2015
Cover w/ Image
Agenda
● JUnit 5.8
● JUnit 5.9
● Spring 5.3
● Spring 6.0
● Q&A
JUnit Jupiter Support in Spring
JUnit Jupiter and Spring are a great match for testing
● Spring Framework
● @ExtendWith(SpringExtension.class)
● @SpringJUnitConfig
● @SpringJUnitWebConfig
● Spring Boot
● @SpringBootTest
● @WebMvcTest, etc.
JUnit 5.8
Major Features in JUnit Platform 1.8
● Declarative test suites via @Suite classes
● SuiteTestEngine in junit-platform-suite-engine module
● new annotations in junit-platform-suite-api module
■ @Suite, @ConfigurationParameter, @SelectUris, @SelectFile, etc.
● UniqueIdTrackingListener
○ TestExecutionListener that tracks the unique IDs of all tests
○ generates a file containing the unique IDs
○ can be used to rerun those tests 
■ for example, with GraalVM Native Build Tools
Example: Suites before 5.8 – Now Deprecated
// Uses JUnit 4 to run JUnit 5
@RunWith(JUnitPlatform.class)
@SuiteDisplayName("Integration Tests")
@IncludeEngines("junit-jupiter")
@SelectPackages("com.example")
@IncludeTags("integration-test")
public class IntegrationTestSuite {
}
Example: Suites with JUnit 5.8
// Uses JUnit 5 to run JUnit 5
@Suite
@SuiteDisplayName("Integration Tests")
@IncludeEngines("junit-jupiter")
@SelectPackages("com.example")
@IncludeTags("integration-test")
public class IntegrationTestSuite {
}
Small Enhancements in JUnit 5.8
https://junit.org/junit5/docs/5.8.0/release-notes/
● More fine-grained Java Flight Recorder (JFR) events
● plus support on Java 8 update 262 or higher
● assertThrowsExactly()
○ alternative to assertThrows()
● assertInstanceOf()
○ instead of assertTrue(obj instanceof X)
● @RegisterExtension fields may now be private
New in JUnit Jupiter 5.8
Test Class Execution Order
● ClassOrderer API analogous to the MethodOrderer API
○ ClassName
○ DisplayName
○ OrderAnnotation
○ Random
● Global configuration via junit.jupiter.testclass.order.default configuration
parameter for all test classes
● for example, to optimize the build
● Local configuration via @TestClassOrder for @Nested test classes
Example: @TestClassOrder
@TestClassOrder(ClassOrderer.OrderAnnotation.class)
class OrderedNestedTests {
@Nested
@Order(1)
class PrimaryTests {
@Test
void test1() {}
}
@Nested
@Order(2)
class SecondaryTests {
@Test
void test2() {}
}
}
@TempDir – New Behavior
Due to popular demand from the community…
● @TempDir previously created a single temporary directory per context
● @TempDir can now be used to create multiple temporary directories
● JUnit now creates a separate temporary directory per @TempDir annotation
● Revert to the old behavior by setting the junit.jupiter.tempdir.scope
configuration parameter to per_context
@ExtendWith on Fields and Parameters
Improves programming model
● @RegisterExtension: register extensions via fields programmatically
○ nothing new
● @ExtendWith: can now register extensions via fields and parameters declaratively
● fields: static or instance
● parameters: constructor, lifecycle method, test method
● typically as a meta-annotation
● avoids the need to declare @ExtendWith at the class or method level
Example: RandomNumberExtension
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(RandomNumberExtension.class)
public @interface Random {
}
class RandomNumberExtension implements BeforeAllCallback,
BeforeEachCallback, ParameterResolver {
// implementation...
}
Example: @Random in Action
class RandomNumberTests {
@Random
private int randomNumber1;
RandomNumberTests(@Random int randomNumber2) {
}
@BeforeEach
void beforeEach(@Random int randomNumber3) {
}
@Test
void test(@Random int randomNumber4) {
}
}
Named API
● Named: container that associates a name with a given payload
○ The meaning of the payload depends on the context
○ Named.of() vs. Named.named()
● DynamicTests.stream() can consume Named input and will use each name-value pair
as the display name and value for each generated dynamic test
● In parameterized tests using @MethodSource or @ArgumentSource, arguments can
now have explicit names supplied via the Named API
○ explicit name used in display name instead of the argument value
Example: Named Dynamic Tests
@TestFactory
Stream<DynamicTest> dynamicTests() {
Stream<Named<String>> inputStream = Stream.of(
named("racecar is a palindrome", "racecar"),
named("radar is also a palindrome", "radar"),
named("mom also seems to be a palindrome", "mom"),
named("dad is yet another palindrome", "dad")
);
return DynamicTest.stream(inputStream,
text -> assertTrue(isPalindrome(text)));
}
AutoCloseable Arguments in Parameterized Tests
● In parameterized tests, arguments that implement AutoCloseable will now be
automatically closed after the test completes
● Allows for automatic cleanup of resources
○ closing a file
○ stopping a server
○ etc.
● Similar to the CloseableResource support in the ExtensionContext.Store
Small Enhancements in JUnit Jupiter 5.8.x
https://junit.org/junit5/docs/5.8.2/release-notes/
● Support for text blocks in @CsvSource
● CSV headers in display names for @CsvSource and @CsvFileSource
● Custom quote character support in @CsvSource and @CsvFileSource
● Java 18 support in the JRE enum
● Access to the ExecutionMode in the ExtensionContext
Example: @CsvSource Before Text Blocks
@ParameterizedTest
@CsvSource({
"apple, 1",
"banana, 2",
"'lemon, lime', 0xF1",
"strawberry, 700_000"
})
void testWithCsvSource(String fruit, int rank) {
assertNotNull(fruit);
assertNotEquals(0, rank);
}
Example: @CsvSource with Text Blocks
@ParameterizedTest
@CsvSource(quoteCharacter = '"', textBlock = """
# FRUIT, RANK
apple, 1
banana, 2
"lemon, lime", 0xF1
strawberry, 700_000
""")
void testWithCsvSource(String fruit, int rank) {
assertNotNull(fruit);
assertNotEquals(0, rank);
}
Example: @CsvSource with CSV Headers
@ParameterizedTest(name = "[{index}] {arguments}")
@CsvSource(useHeadersInDisplayName = true, textBlock = """
FRUIT, RANK
apple, 1
banana, 2
'lemon, lime', 0xF1
strawberry, 700_000
""")
void testWithCsvSource(String fruit, int rank) {
assertNotNull(fruit);
assertNotEquals(0, rank);
}
JUnit 5.9
JUnit Platform 1.9 M1
https://junit.org/junit5/docs/5.9.0-M1/release-notes/
● XML reports in new Open Test 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
JUnit Jupiter 5.9 M1
● Configurable cleanup mode for @TempDir
○ ALWAYS, ON_SUCCESS, NEVER
● New TestInstancePreConstructCallback extension API
○ counterpart to existing TestInstancePreDestroyCallback
● Reusable parameter resolution for custom extension methods via
ExecutableInvoker API
○ accessed via ExtensionContext
○ @BeforeTransaction / @AfterTransaction in Spring?
● @MethodSource factory methods can accept arguments
○ resolved by ParameterResolver extensions
DEMO
@MethodSource and Spring
Spring Framework 5.3
New in Spring Framework 5.3.x (1/2)
https://github.com/spring-projects/spring-framework/releases
● Test configuration is now discovered on enclosing classes for @Nested test classes
● ApplicationEvents abstraction for capturing application events published in the
ApplicationContext during a test
● Set spring.test.constructor.autowire.mode in junit-platform.properties
● Detection for @Autowired violations in JUnit Jupiter
● Improvements for file uploads and multipart support in MockMvc and
MockRestServiceServer
● Various enhancements in MockHttpServletRequest and MockHttpServletResponse
New in Spring Framework 5.3.x (2/2)
● Improved SQL script parsing regarding delimiters and comments
● ExceptionCollector testing utility
● Soft assertions for MockMvc and WebTestClient
● Support for HtmlFileInput.setData() with HtmlUnit and MockMvc
● setDefaultCharacterEncoding() in MockHttpServletResponse
● Default character encoding for responses in MockMvc
Tip: Use Text Blocks... Where you can
● @Sql(statements = …)
○ Just works
● Maybe other places in Spring as well
● Maybe in other frameworks
Example: @Nested tests before 5.3
@SpringJUnitConfig(TestConfig.class)
@ActiveProfiles("dev")
@Transactional
class DevTests {
@Nested
@SpringJUnitConfig(TestConfig.class)
@ActiveProfiles("dev")
@Transactional
class OrderTests { /* tests */ }
@Nested
@SpringJUnitConfig(PricingConfig.class)
class PricingTests { /* tests */ }
}
Example: @Nested tests after 5.3
@SpringJUnitConfig(TestConfig.class)
@ActiveProfiles("dev")
@Transactional
class DevTests {
@Nested
class OrderTests { /* tests */ }
@Nested
@NestedTestConfiguration(OVERRIDE)
@SpringJUnitConfig(PricingConfig.class)
class PricingTests { /* tests */ }
}
Example: ApplicationEvents
@SpringJUnitConfig(/* ... */)
@RecordApplicationEvents
class OrderServiceTests {
@Autowired OrderService orderService;
@Autowired ApplicationEvents events;
@Test
void submitOrder() {
// Invoke method in OrderService that publishes an event
orderService.submitOrder(new Order(/* ... */));
// Verify that 1 OrderSubmitted event was published
assertThat(events.stream(OrderSubmitted.class)).hasSize(1);
}
}
Example: MockMvc without Soft Assertions
mockMvc.perform(get("/person/5").accept(APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Jane"));
Example: MockMvc with Soft Assertions
mockMvc.perform(get("/person/5").accept(APPLICATION_JSON))
.andExpectAll(
status().isOk(),
jsonPath("$.name").value("Jane")
);
Example: WebTestClient without Soft Assertions
webTestClient.get().uri("/test").exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("hello");
Example: WebTestClient with Soft Assertions
webTestClient.get().uri("/test").exchange()
.expectAll(
spec -> spec.expectStatus().isOk(),
spec -> spec.expectBody(String.class).isEqualTo("hello")
);
Example: MockMvc default response character encoding
MockMvc mockMvc;
@BeforeEach
void setup(WebApplicationContext wac) {
this.mockMvc = webAppContextSetup(wac)
.defaultResponseCharacterEncoding(StandardCharsets.UTF_8)
.build();
}
@Test
void getPerson() throws Exception {
this.mockMvc.perform(get("/person/1").characterEncoding(UTF_8))
.andExpect(status().isOk())
.andExpect(content().encoding(UTF_8));
}
Spring Framework 6.0
Testing Enhancements in Spring 6.0
● Module path scanning support
○ for example, when using Maven Surefire and patched modules
○ https://github.com/sbrannen/spring-module-system
● Mechanism for avoiding repeated attempts to load a failing ApplicationContext
○ likely with configurable number of retries
● Accept arguments in @BeforeTransaction and @AfterTransaction methods
● Otherwise, not much else currently planned for 6.0 GA
○ rather for 6.0.x
Q&A
Thank you
Twitter: @sam_brannen
© 2022 Spring. A VMware-backed project.
and JUnit

Testing with JUnit 5 and Spring - Spring I/O 2022

  • 1.
    Sam Brannen @sam_brannen Spring I/O2022 Testing with and Copyright © 2022 VMware, Inc. or its affiliates. JUnit
  • 2.
    ©2020 VMware, Inc.2 This presentation may contain product features or functionality that 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
  • 3.
    Sam Brannen ● StaffSoftware Engineer ● Java Developer for over 20 years ● Spring Framework Core Committer since 2007 ● JUnit 5 Core Committer since October 2015
  • 4.
    Cover w/ Image Agenda ●JUnit 5.8 ● JUnit 5.9 ● Spring 5.3 ● Spring 6.0 ● Q&A
  • 5.
    JUnit Jupiter Supportin Spring JUnit Jupiter and Spring are a great match for testing ● Spring Framework ● @ExtendWith(SpringExtension.class) ● @SpringJUnitConfig ● @SpringJUnitWebConfig ● Spring Boot ● @SpringBootTest ● @WebMvcTest, etc.
  • 6.
  • 7.
    Major Features inJUnit Platform 1.8 ● Declarative test suites via @Suite classes ● SuiteTestEngine in junit-platform-suite-engine module ● new annotations in junit-platform-suite-api module ■ @Suite, @ConfigurationParameter, @SelectUris, @SelectFile, etc. ● UniqueIdTrackingListener ○ TestExecutionListener that tracks the unique IDs of all tests ○ generates a file containing the unique IDs ○ can be used to rerun those tests  ■ for example, with GraalVM Native Build Tools
  • 8.
    Example: Suites before5.8 – Now Deprecated // Uses JUnit 4 to run JUnit 5 @RunWith(JUnitPlatform.class) @SuiteDisplayName("Integration Tests") @IncludeEngines("junit-jupiter") @SelectPackages("com.example") @IncludeTags("integration-test") public class IntegrationTestSuite { }
  • 9.
    Example: Suites withJUnit 5.8 // Uses JUnit 5 to run JUnit 5 @Suite @SuiteDisplayName("Integration Tests") @IncludeEngines("junit-jupiter") @SelectPackages("com.example") @IncludeTags("integration-test") public class IntegrationTestSuite { }
  • 10.
    Small Enhancements inJUnit 5.8 https://junit.org/junit5/docs/5.8.0/release-notes/ ● More fine-grained Java Flight Recorder (JFR) events ● plus support on Java 8 update 262 or higher ● assertThrowsExactly() ○ alternative to assertThrows() ● assertInstanceOf() ○ instead of assertTrue(obj instanceof X) ● @RegisterExtension fields may now be private
  • 11.
    New in JUnitJupiter 5.8
  • 12.
    Test Class ExecutionOrder ● ClassOrderer API analogous to the MethodOrderer API ○ ClassName ○ DisplayName ○ OrderAnnotation ○ Random ● Global configuration via junit.jupiter.testclass.order.default configuration parameter for all test classes ● for example, to optimize the build ● Local configuration via @TestClassOrder for @Nested test classes
  • 13.
    Example: @TestClassOrder @TestClassOrder(ClassOrderer.OrderAnnotation.class) class OrderedNestedTests{ @Nested @Order(1) class PrimaryTests { @Test void test1() {} } @Nested @Order(2) class SecondaryTests { @Test void test2() {} } }
  • 14.
    @TempDir – NewBehavior Due to popular demand from the community… ● @TempDir previously created a single temporary directory per context ● @TempDir can now be used to create multiple temporary directories ● JUnit now creates a separate temporary directory per @TempDir annotation ● Revert to the old behavior by setting the junit.jupiter.tempdir.scope configuration parameter to per_context
  • 15.
    @ExtendWith on Fieldsand Parameters Improves programming model ● @RegisterExtension: register extensions via fields programmatically ○ nothing new ● @ExtendWith: can now register extensions via fields and parameters declaratively ● fields: static or instance ● parameters: constructor, lifecycle method, test method ● typically as a meta-annotation ● avoids the need to declare @ExtendWith at the class or method level
  • 16.
    Example: RandomNumberExtension @Target({ ElementType.FIELD,ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @ExtendWith(RandomNumberExtension.class) public @interface Random { } class RandomNumberExtension implements BeforeAllCallback, BeforeEachCallback, ParameterResolver { // implementation... }
  • 17.
    Example: @Random inAction class RandomNumberTests { @Random private int randomNumber1; RandomNumberTests(@Random int randomNumber2) { } @BeforeEach void beforeEach(@Random int randomNumber3) { } @Test void test(@Random int randomNumber4) { } }
  • 18.
    Named API ● Named:container that associates a name with a given payload ○ The meaning of the payload depends on the context ○ Named.of() vs. Named.named() ● DynamicTests.stream() can consume Named input and will use each name-value pair as the display name and value for each generated dynamic test ● In parameterized tests using @MethodSource or @ArgumentSource, arguments can now have explicit names supplied via the Named API ○ explicit name used in display name instead of the argument value
  • 19.
    Example: Named DynamicTests @TestFactory Stream<DynamicTest> dynamicTests() { Stream<Named<String>> inputStream = Stream.of( named("racecar is a palindrome", "racecar"), named("radar is also a palindrome", "radar"), named("mom also seems to be a palindrome", "mom"), named("dad is yet another palindrome", "dad") ); return DynamicTest.stream(inputStream, text -> assertTrue(isPalindrome(text))); }
  • 20.
    AutoCloseable Arguments inParameterized Tests ● In parameterized tests, arguments that implement AutoCloseable will now be automatically closed after the test completes ● Allows for automatic cleanup of resources ○ closing a file ○ stopping a server ○ etc. ● Similar to the CloseableResource support in the ExtensionContext.Store
  • 21.
    Small Enhancements inJUnit Jupiter 5.8.x https://junit.org/junit5/docs/5.8.2/release-notes/ ● Support for text blocks in @CsvSource ● CSV headers in display names for @CsvSource and @CsvFileSource ● Custom quote character support in @CsvSource and @CsvFileSource ● Java 18 support in the JRE enum ● Access to the ExecutionMode in the ExtensionContext
  • 22.
    Example: @CsvSource BeforeText Blocks @ParameterizedTest @CsvSource({ "apple, 1", "banana, 2", "'lemon, lime', 0xF1", "strawberry, 700_000" }) void testWithCsvSource(String fruit, int rank) { assertNotNull(fruit); assertNotEquals(0, rank); }
  • 23.
    Example: @CsvSource withText Blocks @ParameterizedTest @CsvSource(quoteCharacter = '"', textBlock = """ # FRUIT, RANK apple, 1 banana, 2 "lemon, lime", 0xF1 strawberry, 700_000 """) void testWithCsvSource(String fruit, int rank) { assertNotNull(fruit); assertNotEquals(0, rank); }
  • 24.
    Example: @CsvSource withCSV Headers @ParameterizedTest(name = "[{index}] {arguments}") @CsvSource(useHeadersInDisplayName = true, textBlock = """ FRUIT, RANK apple, 1 banana, 2 'lemon, lime', 0xF1 strawberry, 700_000 """) void testWithCsvSource(String fruit, int rank) { assertNotNull(fruit); assertNotEquals(0, rank); }
  • 25.
  • 26.
    JUnit Platform 1.9M1 https://junit.org/junit5/docs/5.9.0-M1/release-notes/ ● XML reports in new Open Test 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
  • 27.
    JUnit Jupiter 5.9M1 ● Configurable cleanup mode for @TempDir ○ ALWAYS, ON_SUCCESS, NEVER ● New TestInstancePreConstructCallback extension API ○ counterpart to existing TestInstancePreDestroyCallback ● Reusable parameter resolution for custom extension methods via ExecutableInvoker API ○ accessed via ExtensionContext ○ @BeforeTransaction / @AfterTransaction in Spring? ● @MethodSource factory methods can accept arguments ○ resolved by ParameterResolver extensions
  • 28.
  • 29.
  • 30.
    New in SpringFramework 5.3.x (1/2) https://github.com/spring-projects/spring-framework/releases ● Test configuration is now discovered on enclosing classes for @Nested test classes ● ApplicationEvents abstraction for capturing application events published in the ApplicationContext during a test ● Set spring.test.constructor.autowire.mode in junit-platform.properties ● Detection for @Autowired violations in JUnit Jupiter ● Improvements for file uploads and multipart support in MockMvc and MockRestServiceServer ● Various enhancements in MockHttpServletRequest and MockHttpServletResponse
  • 31.
    New in SpringFramework 5.3.x (2/2) ● Improved SQL script parsing regarding delimiters and comments ● ExceptionCollector testing utility ● Soft assertions for MockMvc and WebTestClient ● Support for HtmlFileInput.setData() with HtmlUnit and MockMvc ● setDefaultCharacterEncoding() in MockHttpServletResponse ● Default character encoding for responses in MockMvc
  • 32.
    Tip: Use TextBlocks... Where you can ● @Sql(statements = …) ○ Just works ● Maybe other places in Spring as well ● Maybe in other frameworks
  • 33.
    Example: @Nested testsbefore 5.3 @SpringJUnitConfig(TestConfig.class) @ActiveProfiles("dev") @Transactional class DevTests { @Nested @SpringJUnitConfig(TestConfig.class) @ActiveProfiles("dev") @Transactional class OrderTests { /* tests */ } @Nested @SpringJUnitConfig(PricingConfig.class) class PricingTests { /* tests */ } }
  • 34.
    Example: @Nested testsafter 5.3 @SpringJUnitConfig(TestConfig.class) @ActiveProfiles("dev") @Transactional class DevTests { @Nested class OrderTests { /* tests */ } @Nested @NestedTestConfiguration(OVERRIDE) @SpringJUnitConfig(PricingConfig.class) class PricingTests { /* tests */ } }
  • 35.
    Example: ApplicationEvents @SpringJUnitConfig(/* ...*/) @RecordApplicationEvents class OrderServiceTests { @Autowired OrderService orderService; @Autowired ApplicationEvents events; @Test void submitOrder() { // Invoke method in OrderService that publishes an event orderService.submitOrder(new Order(/* ... */)); // Verify that 1 OrderSubmitted event was published assertThat(events.stream(OrderSubmitted.class)).hasSize(1); } }
  • 36.
    Example: MockMvc withoutSoft Assertions mockMvc.perform(get("/person/5").accept(APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.name").value("Jane"));
  • 37.
    Example: MockMvc withSoft Assertions mockMvc.perform(get("/person/5").accept(APPLICATION_JSON)) .andExpectAll( status().isOk(), jsonPath("$.name").value("Jane") );
  • 38.
    Example: WebTestClient withoutSoft Assertions webTestClient.get().uri("/test").exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo("hello");
  • 39.
    Example: WebTestClient withSoft Assertions webTestClient.get().uri("/test").exchange() .expectAll( spec -> spec.expectStatus().isOk(), spec -> spec.expectBody(String.class).isEqualTo("hello") );
  • 40.
    Example: MockMvc defaultresponse character encoding MockMvc mockMvc; @BeforeEach void setup(WebApplicationContext wac) { this.mockMvc = webAppContextSetup(wac) .defaultResponseCharacterEncoding(StandardCharsets.UTF_8) .build(); } @Test void getPerson() throws Exception { this.mockMvc.perform(get("/person/1").characterEncoding(UTF_8)) .andExpect(status().isOk()) .andExpect(content().encoding(UTF_8)); }
  • 41.
  • 42.
    Testing Enhancements inSpring 6.0 ● Module path scanning support ○ for example, when using Maven Surefire and patched modules ○ https://github.com/sbrannen/spring-module-system ● Mechanism for avoiding repeated attempts to load a failing ApplicationContext ○ likely with configurable number of retries ● Accept arguments in @BeforeTransaction and @AfterTransaction methods ● Otherwise, not much else currently planned for 6.0 GA ○ rather for 6.0.x
  • 43.
  • 44.
    Thank you Twitter: @sam_brannen ©2022 Spring. A VMware-backed project. and JUnit