TransactionalTestExecutionListener manages transactional test execution in Spring’s TestContext framework. With a test annotated @Transactional, setup, execution, and teardown methods run inside a transaction where appropriate, and the transaction rolls back by default. section 20.5 section 20.8
The listener’s behavior has several practical consequences:
- JUnit 5 @BeforeAll and @AfterAll methods execute without an active transaction, while @BeforeEach, the test method, and @AfterEach execute within one. section 20.5
- Use @Commit or @Rollback(false) when a transactional test must commit instead of using the default rollback. section 20.5
- A service method using the default REQUIRED propagation can commit separately from the test transaction, leaving data behind and causing a subsequent repeated test to fail. section 20.5
Observing transaction boundaries
A @SpringBootTest annotated with @Transactional can call TransactionSynchronizationManager.isActualTransactionActive() from lifecycle methods and the test. The expected sequence is false for @BeforeAll and @AfterAll, and true for @BeforeEach, the test, and @AfterEach.
Listing 20.8 The TransactionalTest class
Path: Ch20/1 spring testing/src/test/java/com/manning/javapersistence /testing/TransactionalTest.java @SpringBootTest @Transactional class TransactionalTest { // . . . @BeforeAll static void beforeAll() { System.out.println("beforeAll, transaction active = " + TransactionSynchronizationManager.isActualTransactionActive()); } @BeforeEach void beforeEach() { System.out.println("beforeEach, transaction active = " + TransactionSynchronizationManager.isActualTransactionActive()); } @RepeatedTest(2) void storeRetrieve() { // . . . System.out.println("end of method, transaction active = " + TransactionSynchronizationManager.isActualTransactionActive()); } @AfterEach void afterEach() { System.out.println("afterEach, transaction active = " + TransactionSynchronizationManager.isActualTransactionActive()); } @AfterAll static void afterAll() { System.out.println("afterAll, transaction active = " + TransactionSynchronizationManager.isActualTransactionActive()); } }
Inspect the complete test structure that logs transaction activity across JUnit 5 lifecycle methods. section 20.5
TransactionalTestExecutionListener is one of Spring’s default TestExecutionListeners. Adding a custom listener with @TestExecutionListeners can replace the defaults; use MERGE_WITH_DEFAULTS to retain dependency injection and transactional behavior. section 20.8
