How does @SpringBootTest locate the configuration it uses to build the application context when you don't tell it explicitly?
answer
- Search test package, walk UP to root
- Finds @SpringBootConfiguration (inside @SpringBootApplication)
- Main class in root package by convention
- No classes attr = discovery kicks in
- Full app context, not a slice
basics
~10 sIf you don't specify classes, @SpringBootTest searches the test's package and then walks up parent packages until it finds a class annotated with @SpringBootConfiguration (usually your @SpringBootApplication main class) and uses that.
solid answer
~40 sWhen @SpringBootTest has no explicit configuration, it delegates to @SpringBootConfiguration detection: starting from the test class's package it searches upward through enclosing (parent) packages for exactly one class annotated with @SpringBootConfiguration. In practice that's your @SpringBootApplication class, because @SpringBootApplication is meta-annotated with @SpringBootConfiguration. That found class becomes the primary configuration, and because @SpringBootApplication also enables @ComponentScan and @EnableAutoConfiguration, the test bootstraps the same full context the real app uses. The conventional consequence: put your main application class in the root package (e.g. com.myapp) so every test underneath it discovers it automatically. If none is found — or more than one is — the context fails to start with a clear error.
code
java · 21 lines// src/main/java/com/myapp/Application.java
package com.myapp; // root package
@SpringBootApplication // meta-annotated with @SpringBootConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// src/test/java/com/myapp/web/OrderControllerTest.java
package com.myapp.web;
@SpringBootTest // no classes attribute -> walks up from com.myapp.web
class OrderControllerTest { // -> finds com.myapp.Application
@Autowired ApplicationContext ctx;
@Test void contextLoads() {
assertThat(ctx.containsBean("orderController")).isTrue();
}
}go deeper
Know that omitting classes triggers a search up the package tree for the main app class.
Explain @SpringBootConfiguration vs @SpringBootApplication and the root-package convention.
Discuss failure modes (none/multiple found) and why the full auto-configured context results.
Reason about package topology across multi-module builds and when to bypass discovery entirely.
### The problem it solves A Spring integration test needs to know *which* configuration to load to build the `ApplicationContext` (the container that holds your beans). Spring Boot lets you skip declaring this explicitly and instead *discovers* it by convention. ### The mechanism, step by step 1. `@SpringBootTest` (from `org.springframework.boot.test.context`) checks whether you gave it an explicit configuration via its `classes` attribute (or a nested `@Configuration`, or `@ContextConfiguration`). If you did, discovery is skipped. 2. If you did **not**, it falls back to `@SpringBootConfiguration`-detection, implemented by `SpringBootTestContextBootstrapper` / `AnnotatedClassFinder` (`SpringBootConfigurationFinder`). It starts in the **package of the test class** and looks for a class annotated with `@SpringBootConfiguration`. 3. If it doesn't find one there, it moves **up** to the parent package, then that package's parent, and so on toward the root, until it finds one. 4. `@SpringBootConfiguration` is a specialization of `@Configuration`. Your `@SpringBootApplication` class is annotated with it transitively — `@SpringBootApplication` is meta-annotated with `@SpringBootConfiguration`, `@EnableAutoConfiguration`, and `@ComponentScan`. So the found class is almost always your main app class. ### Why the root-package convention matters Because the search only goes **upward** (toward the root), the main class must sit at or above every test's package. The idiomatic layout is: main class in the root package `com.myapp`, everything else (`com.myapp.web`, `com.myapp.service`) beneath it. Then any test in `com.myapp.**` discovers it. If you bury the main class deep in a sub-package, tests in sibling packages won't find it. ### What you actually get Because the discovered class is `@SpringBootApplication`, the test context includes component scanning of your packages **and** auto-configuration — i.e. the *full* application context, wired much like production (minus the embedded web server unless you ask for one via `webEnvironment`). ### Failure modes - **None found:** startup fails with `Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test`. - **More than one found** in scope: it fails because the primary configuration is ambiguous. ### When to override If you don't want the full app config — or you have a stripped-down test module — pass `@SpringBootTest(classes = SomeConfig.class)` to bypass discovery entirely.
- What annotation is @SpringBootConfiguration a specialization of, and why does that matter?It's a specialization of @Configuration, so a @SpringBootConfiguration class is a full Java configuration class. It matters because discovery keys off @SpringBootConfiguration specifically (not any @Configuration), which is why only the main app class — not arbitrary config classes — is auto-selected.
- What happens if the finder locates two @SpringBootConfiguration classes?The context fails to start because the primary configuration is ambiguous — Spring Boot expects exactly one. You typically hit this only if you accidentally added a second @SpringBootApplication (e.g. a test-only one) in scope; fix it by removing the duplicate or specifying classes explicitly.
saying these in an interview costs you the question
- Saying it scans the whole classpath for any @Configuration (it searches up the package tree for @SpringBootConfiguration specifically)
- Claiming it searches downward into sub-packages
- Thinking it looks for @SpringBootApplication by name rather than the @SpringBootConfiguration meta-annotation