Spring Boot Testing
@SpringBootTest, MockMvc, slice tests, and Testcontainers — fast, real, layered.
# CLAUDE.md — Spring Boot Testing
## Test layers
- **Unit tests** — plain JUnit + Mockito. No Spring context. Fast.
- **Slice tests** — `@WebMvcTest`, `@DataJpaTest`, `@WebFluxTest`. Load only what's needed for one layer.
- **Integration tests** — `@SpringBootTest` with `@AutoConfigureMockMvc` or full HTTP via `TestRestTemplate`/`WebTestClient`.
Most tests should be unit or slice tests. `@SpringBootTest` is slow — use it sparingly, for end-to-end smoke tests.
## @WebMvcTest
- Loads only MVC infrastructure + the controller under test.
- Mock the service layer with `@MockBean`.
- `MockMvc` for assertions:
```java
mvc.perform(get("/users/{id}", "123"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.email").value("a@b"));
```
- Don't `@SpringBootTest` to test a single controller. Use `@WebMvcTest`.
## @DataJpaTest
- Loads JPA + repositories + an in-memory or testcontainers DB.
- Each test runs in a transaction that rolls back. Don't `commit()`.
- Use **Testcontainers Postgres**, not H2. The dialect differences matter:
```java
@Testcontainers
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserRepositoryTest { ... }
```
## @SpringBootTest
- Full app context. Use for end-to-end flows that span multiple layers.
- `webEnvironment = RANDOM_PORT` and `TestRestTemplate`/`WebTestClient` for real HTTP.
- Override beans with `@TestConfiguration` or `@MockBean` — don't fork production wiring with profiles like `test`.
## Testcontainers
- One container per type per test run. Reuse with `@Container` static + `withReuse(true)`:
```java
static PostgreSQLContainer<?> POSTGRES = new PostgreSQLContainer<>("postgres:16-alpine")
.withReuse(true);
static { POSTGRES.start(); }
```
- Configure via `@DynamicPropertySource`:
```java
@DynamicPropertySource
static void props(DynamicPropertyRegistry r) {
r.add("spring.datasource.url", POSTGRES::getJdbcUrl);
}
```
## Test slice tips
- `@MockBean` adds a mock to the application context. Differs from `@Mock`, which is just a Mockito mock.
- Avoid `@MockBean` in unit tests — it forces context loading. Plain `@Mock` is faster.
- `@SpyBean` for partial mocking. Use sparingly — usually a code smell.
## Speed
- Reuse the application context across tests. Boot caches contexts by configuration; don't make every test unique.
- `@DirtiesContext` invalidates the cache. Use it only when you must — it kills performance.
- Run unit tests in parallel: `junit.jupiter.execution.parallel.enabled=true`.
## Don't
- Don't load the full `@SpringBootTest` context for tests that touch one bean.
- Don't use H2 / HSQLDB for repository tests. Use Postgres via Testcontainers.
- Don't share state across tests. Random execution order is the default.
- Don't `Thread.sleep` to wait for async work. Use `Awaitility` or `CompletableFuture.get(timeout)`.
Other Spring Boot templates
Spring Boot 3 Modern Rules
Boot 3+ defaults: starters, configuration properties, profiles, and structured logging.
Spring Boot REST API
RESTful endpoints, OpenAPI/SpringDoc, error model, and response shaping.
Spring Boot Actuator & Observability
Actuator endpoints, Micrometer metrics, structured tracing, and Prometheus.
Spring Boot Deployment
Buildpacks, layered jars, Docker images, and native image with GraalVM.
GraalVM + Spring Boot Native
Spring Boot 3 native compilation, AOT processing, and runtime hints.