Understanding Rebuilds
Spring reuses a cached ApplicationContext only when the test class requesting it produces an identical
MergedContextConfiguration
to one that is already cached. Any difference — however small — forces a full rebuild.
This page explains every property that contributes to that identity, why mismatches happen, and how to prevent them.
Current reporting scope
The rebuild report currently surfaces active profile differences between the cached context and the
class that triggered a rebuild. Differences in other properties — such as @MockBean declarations,
configuration classes, or property overrides — are detected and counted, but are not yet broken out
individually in the output. Per-property diagnosis is planned for a future release.
Causes at a glance
| Cause | Typical trigger | Intentional? |
|---|---|---|
| Active profiles | @ActiveProfiles, spring.profiles.active |
Sometimes |
| Mock and spy beans | @MockBean, @SpyBean |
Usually yes |
@Import on the test class |
Test-specific config added via @Import |
Usually yes |
| Configuration classes | @SpringBootTest(classes = ...) mismatch |
Rarely intentional |
| Property overrides | @TestPropertySource(properties = ...) |
Sometimes |
| Property source locations | @TestPropertySource(locations = ...) |
Rarely |
| Web environment | @SpringBootTest(webEnvironment = ...) mismatch |
Rarely intentional |
| Context initializers | @ContextConfiguration(initializers = ...) |
Usually yes |
| Explicit eviction | @DirtiesContext |
Always intentional |
| Context loader | Custom @ContextConfiguration(loader = ...) |
Rarely |
| Parent context | Nested application context hierarchies | Rarely |
Active profiles
Spring includes the full set of active profiles in the cache key. A context loaded under [test, integration]
and a context loaded under [test] are two distinct entries — even if every other property is identical.
The rebuild report logs
This class profilesandCached context profilesside by side so you can immediately see which profile is missing or extra.
Mock and spy beans
@MockBean and @SpyBean are implemented as context customizers — they are part of the cache key.
Two test classes that declare a different set of mocked beans will always load separate contexts, even
if their profiles and configuration classes match.
@Import on the test class
@Import on a test class is also processed as a context customizer. Two test classes importing a
different set of types produce different cache keys, even when only one extra class is added.
Configuration classes
When classes is specified explicitly in @CacheAwareSpringBootTest(classes = ...), the exact set
of classes is part of the cache key. Mixing explicit declarations with auto-detection, or declaring
different class sets across test classes, prevents reuse.
When all tests need the same explicit classes, centralise the classes declaration on the base class.
When auto-detection works for your module, omit classes entirely — Spring Boot will resolve the
@SpringBootApplication class consistently across all test classes in the same source tree.
Property overrides
Inline properties declared via @TestPropertySource(properties = ...) or
@CacheAwareSpringBootTest(properties = ...) are part of the cache key. Even a single extra or
differing property forces a new context.
Property source locations
@TestPropertySource(locations = ...) points to external property files. Different file paths — or
different sets of files — produce different cache keys.
Web environment
@CacheAwareSpringBootTest(webEnvironment = ...) defaults to MOCK. A class using RANDOM_PORT
cannot share a context with a class using MOCK or NONE, even if everything else is identical.
Context initializers
@ContextConfiguration(initializers = ...) registers ApplicationContextInitializer implementations
that run before the context refreshes. Each distinct set of initializer classes is a separate cache key.
This is commonly seen with Testcontainers, where a shared initializer wires up container connection
properties before the context starts.
Explicit eviction — @DirtiesContext
@DirtiesContext instructs Spring to close and evict the context after the annotated test class (or
method) completes. Any test class that runs after it will receive a REBUILD — this is expected
and intentional.
When a REBUILD after @DirtiesContext appears in the report
This is not a misconfiguration. If @DirtiesContext appears frequently, consider whether the
underlying cause — mutated shared state, a side-effecting operation — can be eliminated so the
annotation is no longer needed.
Context loader
Relevant only when @ContextConfiguration(loader = ...) is used to provide a custom context loader.
Two test classes using different loader implementations will always produce separate cache keys.
Parent context
Relevant only when using Spring's application context hierarchy feature. Different parent context configurations produce different cache keys for child contexts.
The fix in most cases
Every cause above has the same root: configuration that should be shared is declared independently on each test class, and small inconsistencies compound into unnecessary rebuilds. The solution is to centralise everything that must be consistent on a shared abstract base class (or a meta-annotation). Profiles, mocks, web environment, imports — declared once, inherited everywhere.
DO — declare everything that must be consistent on a shared base
DON'T — let each test class declare its own configuration independently
Intentional rebuilds
The goal is not zero rebuilds — it is intentional rebuilds. A test class that genuinely needs
a unique profile, a distinct mock, or @DirtiesContext will always get its own context. The tool
helps you tell the difference between a deliberate choice and an accidental misconfiguration.