All Spring templates

Spring Boot Testing

@SpringBootTest, MockMvc, slice tests, and Testcontainers — fast, real, layered.

DevZone Tools2,160 copiesUpdated Mar 22, 2026Spring BootSpringJava
# 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 templates