skip to content

Explain the mechanism that makes @DataMongoTest exclude your @Service beans, and how you'd customize a data slice (add auto-config, include a bean, change transaction behavior).

level: principalimportance: nice to knowfreq 20%

answer

  1. Two parts: @OverrideAutoConfiguration(false) + TypeExcludeFilter
  2. General auto-config OFF; only Mongo's list turned back on
  3. TypeExcludeFilter drops @Service/@Controller during scan
  4. @Import / nested @TestConfiguration / extra @AutoConfigure to customize
  5. Mongo not @Transactional → manual cleanup; JPA/R2DBC are

basics

~10 s

@DataMongoTest is meta-annotated with @OverrideAutoConfiguration(enabled=false) so only its listed auto-config runs, and a TypeExcludeFilter that filters out @Component/@Service/@Controller during scanning. To customize, use @Import, nested @TestConfiguration, extra @AutoConfigure... annotations, or @AutoConfigureDataMongo attributes.

solid answer

~40 s

The exclusion is two mechanisms working together. First, @DataMongoTest carries @OverrideAutoConfiguration(enabled=false), which switches off Boot's general auto-configuration; only the auto-configuration classes the slice explicitly imports (via @ImportAutoConfiguration/@AutoConfigureDataMongo) are applied — so no web, security, JPA, etc. Second, @TypeExcludeFilters(DataMongoTypeExcludeFilter.class) installs a component-scan filter that rejects your @Component/@Service/@Controller/@Configuration classes, keeping only slice-relevant types (@Document, converters, repositories). To customize: add a specific collaborator with @Import(Foo.class); add test-only beans with a nested static @TestConfiguration; widen the context by stacking another @AutoConfigure... (e.g., @AutoConfigureJson); and configure the slice via annotation attributes or properties. You can also include normally-excluded types by combining @Import with the class, or fall back to @SpringBootTest when customization defeats the purpose. Mongo isn't rollback-transactional, so cleanup is manual.

code

java · 25 lines
java
@DataMongoTest
@Import(PricingService.class)   // pull one collaborator past the type filter
class PricingServiceMongoTest {

    @Container @ServiceConnection
    static MongoDBContainer mongo = new MongoDBContainer("mongo:7");

    @TestConfiguration
    static class Extra {
        @Bean MongoCustomConversions conversions() {
            return new MongoCustomConversions(List.of(new MoneyReadConverter()));
        }
    }

    @Autowired PricingService pricingService;  // resolvable because of @Import
    @Autowired MongoTemplate mongoTemplate;

    @AfterEach void cleanUp() {
        mongoTemplate.getDb().drop();  // no rollback — clean manually
    }

    @Test void pricesFromStoredRules() {
        // ... arrange docs, exercise service, assert
    }
}

go deeper

for a junior

Know that the slice hides your services and you can @Import to add one back.

for a middle

Explain @Import vs @TestConfiguration and that Mongo needs manual cleanup (no rollback).

for a senior

Describe @OverrideAutoConfiguration + TypeExcludeFilter, widening/excluding auto-config, and @ServiceConnection/@DynamicPropertySource wiring.

for a principal

Reason about context-cache fragmentation from customization, when customization defeats the slice and you should escalate to @SpringBootTest, and the transaction-manager implications of forcing @Transactional on Mongo.

**The two-part exclusion machinery.** `@DataMongoTest` (like every slice) is a *composed annotation*. Two meta-annotations do the filtering: 1. **`@OverrideAutoConfiguration(enabled = false)`** — Spring Boot normally applies *all* matching auto-configuration (`@EnableAutoConfiguration`). This meta-annotation flips a flag that disables that blanket auto-configuration. The slice then *re-enables only what it needs* by also carrying `@ImportAutoConfiguration`-style annotations (surfaced as `@AutoConfigureDataMongo`, `@AutoConfigureCache`, etc.), whose entries come from `META-INF/spring.factories` / `META-INF/spring/...AutoConfiguration.imports`. Net effect: web server, Spring Security, JPA, other datastores are simply never configured — not because they're excluded one by one, but because general auto-config is off and only Mongo's list is turned back on. 2. **`@TypeExcludeFilters(DataMongoTypeExcludeFilter.class)`** — a `TypeExcludeFilter` is a Boot extension point plugged into component scanning. `DataMongoTypeExcludeFilter` (a subclass of `StandardAnnotationCustomizableTypeExcludeFilter`) *excludes* your stereotype-annotated classes (`@Component`, `@Service`, `@Controller`, `@RestController`, `@Configuration` that aren't slice-relevant) while *including* the slice's own relevant types (`@Document`, converters, repositories). This is why an `@Autowired MyService` fails to resolve in a plain slice test. Together: (1) keeps unrelated *auto-configured* infrastructure out; (2) keeps your *scanned application* beans out. That's the whole isolation story. **Customizing a slice.** - **Include one collaborator:** `@Import(MyService.class)` on the test class registers that bean even though the type filter would otherwise skip it. Ideal when the persistence test genuinely needs a thin wrapper service. - **Add test-only beans / overrides:** a nested `static @TestConfiguration` class is picked up in addition to the slice (unlike `@Configuration` in the same file, `@TestConfiguration` is not treated as the primary config and won't disable slice behavior). Use it to define a custom `MongoCustomConversions`, a test clock, etc. - **Widen auto-configuration:** because general auto-config is off, adding a capability means adding its `@AutoConfigure...` annotation, e.g. `@AutoConfigureJson`, or importing a specific `XxxAutoConfiguration` with `@ImportAutoConfiguration`. Stacking too many is a smell — prefer `@SpringBootTest`. - **Exclude something the slice pulls in:** `@DataMongoTest(excludeAutoConfiguration = SomeAutoConfiguration.class)` or the general `@ImportAutoConfiguration`/`spring.autoconfigure.exclude` mechanisms. - **Slice attributes / properties:** use `@TestPropertySource`, `@DynamicPropertySource` (common for pointing at a Testcontainers URI before `@ServiceConnection` existed), or `properties = {"..."}` on the annotation. **Transaction behavior.** Slices that target transactional stores (`@DataJpaTest`, `@DataJdbcTest`, `@DataR2dbcTest`) are meta-annotated `@Transactional`, so each test runs in a transaction rolled back afterward for isolation. `@DataMongoTest` is **not** — MongoDB single-node historically had no transactions, so there's no automatic rollback. If you want transactional behavior you'd need a replica-set-backed Mongo and an explicit `MongoTransactionManager`, but for tests the pragmatic approach is manual cleanup: drop collections in `@AfterEach`, use a fresh Testcontainers instance per class, or `mongoTemplate.getDb().drop()`. You *can* add `@Transactional` yourself, but without a configured transaction manager and transaction-capable Mongo it won't give JPA-style rollback. **Backing store & context caching.** The slice still needs a real Mongo — Testcontainers `MongoDBContainer` with `@ServiceConnection` (Boot 3.1+) auto-wires the URI; before that, `@DynamicPropertySource` set `spring.data.mongodb.uri`. Keep the slice configuration identical across test classes so Spring's `ContextCache` reuses one context (and one container if it's a static/shared field) — differing `@Import`/property sets fragment the cache and multiply startup cost. **When customization is the wrong tool.** If you find yourself importing several services, widening auto-config, and adding property sources, the slice's speed/isolation payoff is gone. That's the signal to use `@SpringBootTest` (optionally with `@ServiceConnection`) — it's simpler and more faithful for genuinely cross-layer tests.

  • Why does an @Autowired MyService fail in a plain @DataMongoTest but a repository interface resolves fine?
    The DataMongoTypeExcludeFilter excludes @Service (and other stereotypes) from component scanning, so MyService is never registered. Repository interfaces are slice-relevant types that the Mongo auto-config creates, so they resolve. Adding @Import(MyService.class) forces the service in.
  • How would you point the slice at a Testcontainers Mongo before @ServiceConnection existed?
    Use @DynamicPropertySource: a static method receiving a DynamicPropertyRegistry that registers spring.data.mongodb.uri (or host/port) from the started container, so the Mongo auto-config connects to it. @ServiceConnection (Boot 3.1+) automates exactly this.
  • A colleague adds @Transactional to a @DataMongoTest expecting rollback. Does it work?
    Not by default. Without a configured MongoTransactionManager and a transaction-capable (replica-set) Mongo, @Transactional gives no JPA-style rollback. The slice isn't meta-annotated @Transactional for good reason; use explicit cleanup instead.

saying these in an interview costs you the question

  • Thinking @Transactional on @DataMongoTest yields rollback like JPA
  • Believing the slice individually excludes web/security rather than disabling general auto-config
  • Assuming @Configuration in the test file behaves like @TestConfiguration
  • Widening a slice with many @Import/@AutoConfigure instead of moving to @SpringBootTest

context