Interview Prep Zoneby CuriouserLabs

Question 4 of 5 · staff level

Your integration suite takes 20 minutes. Explain Spring's test context caching and how you'd fix the suite.

🎤 Say this first

Spring caches ApplicationContexts across tests keyed by configuration: same context config = reuse (fast); anything that changes the key — different @ActiveProfiles, @TestPropertySource, @MockitoBean sets, @DirtiesContext, different slice combos — forks a new context (each = full app startup). Twenty-minute suites are almost always context-cache-miss storms. Fix: audit unique configurations (log ContextCache stats), consolidate into a few shared base test configurations, ban casual @DirtiesContext, centralize mocks/fakes, and move logic tests down the pyramid where Spring isn't needed.

The full picture

  1. Measure first: run with logging.level.org.springframework.test.context.cache=DEBUG — it prints cache hits/misses and context count. >5 distinct contexts for one service should raise eyebrows.
  2. Standardize the key: one AbstractIntegrationTest (annotations, containers, profile) that all ITs extend — every deviation is a review conversation.
  3. Mock hygiene: each unique @MockitoBean combination = new context. Group mocks into shared @TestConfiguration classes; or replace boundary mocks with singleton fakes/WireMock so the context stays identical.
  4. @DirtiesContext is a fire alarm, not a doorstop: it exists for tests that genuinely corrupt global state; used as a flakiness bandaid it turns O(1) contexts into O(n).
  5. Parallelize what's parallel-safe: JUnit parallel execution + independent data (unique keys per test) — after the cache is fixed, not before.
One context to rule the ITs
@SpringBootTest(webEnvironment = RANDOM_PORT)
@ActiveProfiles("it")
@Import(SharedTestBeans.class)          // ALL common fakes live here
@Testcontainers
public abstract class AbstractIT {
    @Container @ServiceConnection
    static final PostgreSQLContainer<?> DB = Containers.postgres(); // singleton
}

class OrderFlowIT extends AbstractIT { … }   // cache HIT
class RefundFlowIT extends AbstractIT { … }  // cache HIT — same key, same context

🔄 Likely follow-up questions

  • What exactly composes the context cache key?
  • How do you find which test introduced a new context in a big repo?
  • When is @DirtiesContext genuinely correct?