Testing — Slices & Testcontainers

Overview

Spring Boot tests come in layers. Use the smallest annotation that loads only what you need. Full context is slow; slices load just one layer.

Official: Spring Boot Testing.


Table of contents

  1. Annotation cheat sheet
  2. @SpringBootTest
  3. @WebMvcTest
  4. @DataJpaTest
  5. @MockBean and context caching
  6. Testcontainers
  7. @DynamicPropertySource
  8. Interview questions
  9. Summary

1. Annotation cheat sheet

Annotation Loads
@SpringBootTest Full (or near-full) application context
@WebMvcTest Web layer only (controllers, Jackson, validation)
@DataJpaTest JPA repositories + embedded DB
@JsonTest Jackson serialisation only
@RestClientTest One HTTP client + its mocks

2. @SpringBootTest

Loads everything. Use for integration tests where you genuinely need wiring.

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class OrderApiIT { ... }

webEnvironment options:

  • MOCK (default) — mock servlet env, no real port.
  • RANDOM_PORT — real Tomcat on a random port (good for TestRestTemplate / WebTestClient).

Slow → use sparingly. Use slices first.


3. @WebMvcTest

Tests controllers without booting the full app.

@WebMvcTest(OrderController.class)
class OrderControllerTest {
    @Autowired MockMvc mvc;
    @MockBean OrderService service;

    @Test
    void returns404() throws Exception {
        when(service.find(1L)).thenThrow(new NotFoundException());
        mvc.perform(get("/api/orders/1"))
           .andExpect(status().isNotFound());
    }
}

Loads @RestController, validation, Jackson — not services or JPA.


4. @DataJpaTest

Tests repositories against an embedded DB (H2 by default).

@DataJpaTest
class OrderRepositoryTest {
    @Autowired OrderRepository orders;
    // test queries
}

Use @AutoConfigureTestDatabase(replace = NONE) to keep your real DB driver (e.g. when using Testcontainers).


5. @MockBean and context caching

Spring caches test contexts between tests for speed. Each distinct combination of @MockBean becomes a new cache key, so many varied mock setups cause context churn and slow suites.

Rule of thumb: prefer plain Mockito unit tests when no Spring wiring is needed. Use @MockBean only when Spring must inject the mock into the system under test.


6. Testcontainers

Spin up a real Postgres/Kafka/Redis in Docker for the test:

@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
@Testcontainers
class OrderRepositoryIT {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");

    @DynamicPropertySource
    static void props(DynamicPropertyRegistry r) {
        r.add("spring.datasource.url", postgres::getJdbcUrl);
        r.add("spring.datasource.username", postgres::getUsername);
        r.add("spring.datasource.password", postgres::getPassword);
    }
}

Real SQL dialect → catches issues H2 hides.


7. @DynamicPropertySource

Injects property values into Spring’s Environment before the context refreshes. Standard pattern for Testcontainers URLs/ports.


8. Interview questions

Q: @WebMvcTest vs @SpringBootTest? A: @WebMvcTest loads only the web layer (fast, focused). @SpringBootTest loads everything (slow, integration).

Q: Why can @MockBean slow down a test suite? A: Each unique mock combination triggers a new test context, which forces a context restart.

Q: What is Testcontainers for? A: Running real databases, Kafka, Redis in Docker during integration tests so you don’t rely on H2 quirks.

Q: What does @DynamicPropertySource do? A: Adds properties to Spring’s environment before context refresh — used for container URLs/ports.


9. Summary

Annotation Loads Speed
@SpringBootTest Everything Slow
@WebMvcTest Web slice Fast
@DataJpaTest JPA + DB Medium
Plain Mockito Nothing Spring Fastest

Next steps


Happy Learning

Next: Actuator, Metrics & Observability