test: convert eligible integration tests to @Transactional#24014
Merged
Conversation
Convert 7 non-@transactional integration tests to @transactional so the SpringIntegrationTestExtension cleans up via cheap rollback instead of the expensive dbmsManager.emptyDatabase() truncate-all run per test method. Tests whose reads go through raw jdbcTemplate SQL (or whose write happens via session.doWork on the shared connection) get an explicit entityManager.flush() so those reads see the un-committed session writes within the same transaction. Measured ~52% reduction in per-class execution time on the 6 separable converted classes in a shared-context run (each ~halves, consistent with eliminating one emptyDatabase() truncate per test method). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
netroms
approved these changes
May 31, 2026
enricocolasante
approved these changes
Jun 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Follow-up to #24012. Converts a further 7 non-
@Transactionalintegration tests indhis-test-integrationto@Transactional, soSpringIntegrationTestExtensioncleans upbetween tests via a cheap transaction rollback instead of the expensive
dbmsManager.emptyDatabase()truncate-all that runs once per test method fornon-transactional,
PER_METHODclasses.Where a test reads back through raw
jdbcTemplateSQL (which does not trigger Hibernateauto-flush) or writes via
session.doWorkon the shared connection, an explicitentityManager.flush()is added so those reads see the un-committed session writes within thesame transaction.
jdbcTemplateand Hibernate share the transaction-bound connection under@Transactional, so a flush (not a commit) is sufficient.This was the careful, per-class audit called for in improvement plan #2 — each conversion was
verified green individually; classes that could not be safely converted were left unchanged with
the reason recorded (see below).
Changes (file by file)
PostgreSqlBuilderInheritanceIntegrationTest@TransactionalonlyPredictorServiceTest@Transactional+ flush before the delete-vetoassertThrowsDeleteNotAllowedExceptionis an app-level veto backed by a raw-SQL count onpredictor; the predictor rows must be flushed first.ProgramStageDataElementServiceTest@Transactional+ 2 flushesgetProgramStageDataElementsWithSkipSynchronizationSetToTrue).DataOrgUnitMergeHandlerTest@Transactional+ flush in setUp &addDataApprovalsNamedParameterJdbcTemplate; approvals written via Hibernate must be flushed.DataApprovalStoreUserTest@Transactional+ flush before readHibernateDataApprovalStore.getDataApprovalStatusesis raw jdbc.DataApprovalServiceCategoryOptionGroupTest@Transactional+ flush in setUp & in approve/unapprove/accept/unaccept helpersDataStatisticsEventStoreTest@Transactional+ flush at end of setUpHibernateDataStatisticsEventStorereads are raw jdbc.Performance
Single shared-context JVM, surefire per-class "Time elapsed", master baseline vs branch:
Sum of those 6 separable classes: 9.62s → 4.63s (−51.9%) — each roughly halves, consistent
with removing one
emptyDatabase()truncate per test method. (DataApprovalServiceCategoryOptionGroupTestalso converted, but it absorbs the one-time Spring context startup in a shared-JVM run, so its own
saving isn't separable from the startup it carries.)
Caveat: single run, shared-context JVM; the full-suite sum is dominated by the one ~startup the
run carries, so the per-class deltas are the meaningful signal. Real CI (sharded, per-shard
startup) will differ in absolute terms — the win is removing work done, not just wall-clock.
Deferred (audited, intentionally NOT converted)
TrackedEntityAggregate.find()→ can't see un-committed data, flush can't bridge):PotentialDuplicateRemoveTrackedEntityTest,DeduplicationServiceMergeIntegrationTest,MaintenanceServiceTest.assertThrowsexpectsDataIntegrityViolationException,but a raw
em.flush()throws untranslatedjakarta.persistence.PersistenceException;translation only happens at tx commit / via
@Repositoryproxy):TrackedEntityTypeServiceTest,UidDBConstraintCheckTest.preheat don't see un-committed data even with a setUp flush — import returns 0 rows):
AdxDataServiceIntegrationTest,DataExportServiceExportTest,DataExportServiceIntegrationTest.Test plan
mvn test -pl dhis-test-integration -am -Pintegration-test -Dtest=<7 classes>→ BUILD SUCCESS, all greenmvn spotless:check -pl dhis-test-integrationpasses🤖 Generated with Claude Code