A persistence-context cache can make a repository test pass without proving that the database contains the expected row.
Spring Data JPA test: flush and clear before trusting a read
Test the stored state
A repository test saves a receipt, then calls findById in the same persistence context. JPA may hand back the already managed object. That proves little about column mapping, database defaults, or a query predicate. Flush pending SQL, clear the persistence context, then read again. A flush can expose a constraint failure, while the clear forces a later lookup to materialize data from the database. Flush remains different from commit].
Choose the assertion boundary
For a derived tenant query, persist one local receipt and one foreign-tenant receipt, flush and clear, then assert only the local row appears. A unit mock cannot validate JPQL or the actual tenant predicate. For a test of joined page totals], seed multiple matching child rows and assert both content and totalElements after clearing. Keep the dataset small enough to diagnose a failure, but varied enough to expose row multiplication.
Account for rollback
@DataJpaTest normally wraps each test in a transaction and rolls it back. That isolates many repository tests, but it does not prove a commit-time constraint, an after-commit listener, or what another transaction sees. Use a separate committed-boundary test for those contracts. If you inspect SQL counts, reset the counter after setup; fixture inserts otherwise contaminate the measurement.
Implementation contract
@DataJpaTest
class ReceiptTenantQueryTest {
@Autowired ReceiptRepository receipts;
@Autowired EntityManager entityManager;
@Test void excludesOtherTenantAfterDatabaseRoundTrip() {
receipts.save(ReceiptEntity.forTenant(NORTH_TENANT, "R-47"));
receipts.save(ReceiptEntity.forTenant(SOUTH_TENANT, "R-47"));
entityManager.flush();
entityManager.clear();
assertThat(receipts.findByTenantId(NORTH_TENANT))
.extracting(ReceiptEntity::getTenantId)
.containsExactly(NORTH_TENANT);
}
}Cost and verification
Flush adds a database synchronization point; clear discards managed objects and requires another read. That extra work is useful in persistence tests but would be needless ceremony in a plain unit test with no JPA context.
Common Mistakes
- Do not assert against the same managed entity and call it a database round trip.
- Do not treat a rolled-back slice test as proof of commit-time behavior.
- Do not include setup statements in the query budget being measured.
Read next
Spring Data JPA saveAndFlush is a SQL boundary, not a commit, Spring Data JPA count query for a joined Page, Spring Data JPA Specifications with a mandatory tenant predicate, Spring Data JPA test against the deployment database dialect, Spring command rollback test: inspect state after an injected failure.
