Profiles, property overrides, bean overrides and test configuration affect whether Spring can reuse an application context.
Spring TestContext cache: keep equivalent tests on one context shape
A cached context has a key
Two integration tests that request equivalent configuration can share one cached ApplicationContext inside a test process. Add a different active profile, a per-class property, or a distinct @MockitoBean override and the cache key may differ; startup work repeats. The cache is process-local, so separate build forks do not share it. Context tests] should prove wiring, not create a fresh application for every assertion.
Consolidate by contract
Group tests that need the same profile, database connection and bean graph. Use explicit fixtures and reset test data between methods instead of changing properties merely to alter a row value. Avoid @DirtiesContext as routine cleanup: it evicts the context and makes later tests pay startup cost again. Never share mutable singleton test state across classes without reset; a fast reused context must still be isolated at the data and mock level.
Measure before restructuring
Enable test-context cache statistics while running the suite and inspect hit, miss and eviction counts. Change one configuration dimension at a time, then rerun the same set. A context cache hit is useful only if the test still covers production-relevant wiring. Container ownership] can add its own lifecycle and property differences.
Implementation contract
@SpringBootTest
@ActiveProfiles("integration")
@Transactional
abstract class ReceiptIntegrationContext {
@Autowired protected ReceiptRepository receipts;
}
class ReceiptLookupIT extends ReceiptIntegrationContext {
@Test void tenantQueryDoesNotLeakRows() {
UUID north = UUID.randomUUID();
UUID south = UUID.randomUUID();
receipts.save(ReceiptEntity.forTenant(north, "R-47"));
receipts.save(ReceiptEntity.forTenant(south, "R-48"));
assertThat(receipts.findByTenantId(north))
.extracting(ReceiptEntity::getTenantId)
.containsExactly(north);
}
}Cost and verification
Context startup can dominate a small test suite. Reuse saves startup time and memory, while overly broad contexts increase the cost of each miss. Cache size and build forking limit the benefit; measure suite wall time, not annotation count.
Common Mistakes
- Do not add per-class profile or property overrides without recognizing the cache-key cost.
- Do not use @DirtiesContext as a substitute for fixture cleanup.
- Do not share unreset mutable state just to gain a cache hit.
Read next
Spring ApplicationContextRunner: check conditional assembly in isolation, Spring @MockitoBean override: a mock can remove advice from the tested bean, Spring Boot Testcontainers: service connections and cached-context lifecycle, Spring tests: separate business rules, wiring and transport, Spring Boot config tests: what a child JVM proves and what deployment still owes.
Related test contract
Spring @DynamicPropertySource: bind test resources without stale cached values.
Related test contract
Spring @DirtiesContext: evict only a context a test truly changed.
