When would you choose @DataMongoTest over @SpringBootTest, and what are the trade-offs?
answer
- Slice = fast + isolated persistence tests
- Full context = cross-layer / e2e, slower
- @Import a service into the slice, don't over-widen
- Test pyramid: many slices, few @SpringBootTest
- Both need real Mongo (Testcontainers)
basics
~10 sUse @DataMongoTest when you only test the persistence layer (repositories, MongoTemplate): it starts a smaller context, so tests are faster and more isolated. Use @SpringBootTest when behavior crosses layers or needs many beans.
solid answer
~40 s@DataMongoTest loads a narrow slice — Mongo repositories, MongoTemplate, converters, @Document scanning — and excludes web, security, and your service beans. That makes persistence tests fast, focused, and less brittle: a query bug fails here without noise from unrelated beans. Prefer it for repository query derivation, custom @Query methods, aggregations, index behavior, and converter mapping. The trade-off is that collaborators aren't present, so you @Import only what you need, and cross-layer behavior (controller→service→repo) isn't exercised. @SpringBootTest loads the full context (optionally with a running web server), which is right for end-to-end or multi-layer integration tests but is slower and can mask which layer broke. A healthy suite has many fast slice tests and a few broad @SpringBootTest ones. Both typically use Testcontainers for a real Mongo.
go deeper
Know the slice is faster and tests only the repository layer; full context is for end-to-end.
Articulate the isolation/speed vs coverage trade-off and when @Import is fine vs when to move to @SpringBootTest.
Bring in context caching, the test pyramid, and cleanup implications of the non-transactional slice.
Set suite-wide policy: which behaviors get slices vs full context, container reuse strategy, and how to keep context-cache fragmentation low.
**The two ends of Spring Boot integration testing.** `@SpringBootTest` bootstraps the *entire* application context — every bean, every auto-configuration, optionally a real embedded web server (`webEnvironment = RANDOM_PORT`). It is the most faithful but the heaviest. A *slice* annotation like `@DataMongoTest` loads only the auto-configuration for one concern (MongoDB persistence) and deliberately excludes everything else. **What @DataMongoTest gives and withholds.** It wires `MongoTemplate`/`ReactiveMongoTemplate`, your `MongoRepository`/`ReactiveMongoRepository` interfaces, the mapping converters, and scans `@Document` types. It does **not** scan your `@Service`, `@Controller`, `@Component`, does not start the web layer, and does not configure Spring Security. This is enforced via a `TypeExcludeFilter` and `@OverrideAutoConfiguration(enabled=false)`. **Why choose the slice.** - **Speed.** Fewer beans and no web server means the context starts in a fraction of the time. Across hundreds of tests this dominates suite runtime. Spring also *caches* contexts by configuration, so many slice tests that share the same setup reuse one context. - **Isolation / diagnosis.** If a derived query like `findByStatusAndCreatedAtAfter` is wrong, a slice test fails pointing straight at persistence — no unrelated bean wiring, no mocked services muddying the signal. - **Focus.** You test exactly the mapping/query layer: converters, `@Query` JSON, aggregation pipelines via `MongoTemplate`, index creation, optimistic locking with `@Version`. **Costs of the slice.** - Collaborators aren't present. If the thing under test genuinely needs a `@Service`, you must `@Import` it, and if that service pulls in more beans the slice starts to erode — at which point `@SpringBootTest` is cleaner. - It does not verify cross-layer wiring (serialization at the controller, security rules, transaction boundaries spanning services). Those need broader tests. **Why choose @SpringBootTest.** - Multi-layer or end-to-end behavior: HTTP request → controller → service → repository → Mongo, asserting the whole path. - You need beans from several slices at once, or custom `@Configuration` that only makes sense in the full context. - Trade-off: slower startup, and a failure can be harder to localize because everything is present. **Getting the database.** Both approaches still need a real MongoDB. The modern answer is Testcontainers with `@ServiceConnection` (Boot 3.1+) so the container URI is auto-wired. Context caching interacts with containers: keep container/config identical across tests to reuse the cached context and avoid restarting Mongo. **Rule of thumb (test pyramid).** Push most persistence coverage into fast `@DataMongoTest` slices; keep a small number of `@SpringBootTest` integration tests for the critical end-to-end flows. Reserve pure unit tests (no Spring context at all) for logic that doesn't touch the database. **Gotcha — data cleanup.** Because `@DataMongoTest` is not rollback-transactional, writes persist between tests unless you clean collections (`@AfterEach` drop) or recreate the container. `@SpringBootTest` with Mongo has the same concern. Don't assume the JPA-style automatic rollback.
- Your slice test keeps needing more and more @Import to satisfy dependencies. What does that signal?It signals the test is really an integration test spanning layers. Once you're importing a web of beans, switch to @SpringBootTest — you lose the slice's speed/isolation benefit anyway and gain simpler, more faithful wiring.
- How does Spring's context caching affect the choice?Spring caches a context per unique configuration. Many slice tests sharing identical config reuse one cached context, so startup cost is paid once. Mixing many different @SpringBootTest configurations fragments the cache and slows the suite.
saying these in an interview costs you the question
- Using @SpringBootTest for everything because 'it's more realistic'
- Mocking the repository in a test meant to verify the real query
- Piling @Import until the slice is effectively a full context
- Assuming slice tests auto-clean data between runs