Cheat SheetsSpring BootTesting

Testing — Cheat Sheet

Spring Boot · 5 topics. Download the PDF or the Instagram carousel and share it.

Cheat Sheet · AiCanCode.org
Testing
Spring Boot5 topicsQuick revision reference
1

@SpringBootTest

@SpringBootTest loads the full application context for integration tests; use webEnvironment=RANDOM_PORT for tests that exercise the real HTTP stack.

  • @SpringBootTest(webEnvironment=RANDOM_PORT) starts a real server — use TestRestTemplate for HTTP calls; best for end-to-end smoke tests.
  • @WebMvcTest loads only the MVC layer — fast controller tests; mock all service and repository beans with @MockBean.
  • @DataJpaTest loads only JPA + in-memory H2 and rolls back each test — ideal for testing @Query correctness.
  • @MockBean replaces the real Spring bean with a Mockito mock; @SpyBean wraps the real bean (real methods unless stubbed).
  • Prefer test slices over full @SpringBootTest for speed — only use @SpringBootTest for true end-to-end integration tests.
  • Use @TestPropertySource or @SpringBootTest(properties=…) to override application.yml values for specific tests.
Java — @SpringBootTest
// Full integration test — real HTTP stack, random port
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OrderControllerIntegrationTest {

    @Autowired
    TestRestTemplate restTemplate;  // auto-configured for RANDOM_PORT

    @Test
    void placeOrder_shouldReturn201AndOrderId() {
        OrderRequest request = new OrderRequest("PROD-1", 2);

        ResponseEntity<OrderResponse> response = restTemplate.postForEntity(
            "/api/orders", request, OrderResponse.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
        assertThat(response.getBody().getOrderId()).isNotNull();
    }
}

// No server — test service layer directly
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
class OrderServiceIntegrationTest {
    @Autowired OrderService orderService;
    @Autowired OrderRepository orderRepository;

    @Test
    @Transactional
    void placeOrder_shouldPersistOrder() {
        Order order = orderService.placeOrder(new OrderRequest("PROD-1", 2));
        assertThat(orderRepository.findById(order.getId())).isPresent();
    }
}
2

MockMvc Testing

MockMvc dispatches requests through the MVC pipeline without starting a real server, enabling fast controller tests with request/response assertions.

  • Standalone setup tests the controller in isolation (no Spring context) — fastest; use for unit tests.
  • @AutoConfigureMockMvc with @SpringBootTest tests the full pipeline including security filters and real beans.
  • @MockBean replaces a real Spring bean in the context with a Mockito mock — needed when using @SpringBootTest.
  • @WithMockUser (spring-security-test) injects a mock authentication into the SecurityContext for security tests.
  • andDo(print()) logs the full request/response to stdout — invaluable during test development.
  • jsonPath uses Jayway JsonPath syntax: $.content[0].id, $.totalElements, $.content.length().
Java — standalone MockMvc controller unit test
@ExtendWith(MockitoExtension.class)
class OrderControllerTest {

    @Mock
    private OrderService orderService;

    private MockMvc mockMvc;

    @BeforeEach
    void setUp() {
        mockMvc = MockMvcBuilders
            .standaloneSetup(new OrderController(orderService))
            .setControllerAdvice(new GlobalExceptionHandler()) // include if needed
            .build();
    }

    @Test
    void getOrder_returnsOrder() throws Exception {
        Order order = new Order(1L, "PENDING", new BigDecimal("99.99"));
        when(orderService.findById(1L)).thenReturn(order);

        mockMvc.perform(get("/api/orders/1")
                .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id").value(1))
            .andExpect(jsonPath("$.status").value("PENDING"))
            .andExpect(jsonPath("$.total").value(99.99));

        verify(orderService).findById(1L);
    }

    @Test
    void createOrder_validatesInput() throws Exception {
        String invalidJson = """{"customerId": null, "total": -10}""";

        mockMvc.perform(post("/api/orders")
                .contentType(MediaType.APPLICATION_JSON)
                .content(invalidJson))
            .andExpect(status().isBadRequest())
            .andExpect(jsonPath("$.errors").isArray());
    }
}
3

@WebMvcTest

Slices the context to only MVC infrastructure and the specified controller, making tests lighter; beans not in scope must be mocked with @MockBean.

  • @WebMvcTest loads only MVC infrastructure — faster than @SpringBootTest but tests the real MVC pipeline.
  • All service/repository beans must be provided via @MockBean; they are not auto-scanned in the slice.
  • Spring Security IS included; use @WithMockUser, @WithAnonymousUser, or mock UserDetailsService as needed.
  • @ControllerAdvice beans are automatically included in the slice — test exception handler mappings here.
  • Specify the controller class in @WebMvcTest(MyController.class) to load only that controller and reduce context size.
  • Use @Import to add custom beans or configuration to the slice without loading the full application context.
Java — @WebMvcTest with @MockBean service
@WebMvcTest(OrderController.class)  // only loads OrderController + MVC infrastructure
class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @MockBean                           // provides mock to OrderController
    private OrderService orderService;

    @MockBean
    private OrderMapper orderMapper;

    @Test
    void getOrder_found_returns200() throws Exception {
        OrderDto dto = new OrderDto(1L, "PENDING", new BigDecimal("99.99"));
        when(orderService.findById(1L)).thenReturn(dto);

        mockMvc.perform(get("/api/orders/1"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id").value(1))
            .andExpect(jsonPath("$.status").value("PENDING"));
    }

    @Test
    void getOrder_notFound_returns404() throws Exception {
        when(orderService.findById(99L))
            .thenThrow(new OrderNotFoundException(99L));

        mockMvc.perform(get("/api/orders/99"))
            .andExpect(status().isNotFound())
            .andExpect(jsonPath("$.message").value("Order 99 not found"));
    }

    @Test
    void createOrder_invalidBody_returns400() throws Exception {
        // empty customerId triggers @NotBlank validation
        String json = """{"customerId":"","total":50.0}""";

        mockMvc.perform(post("/api/orders")
                .contentType(MediaType.APPLICATION_JSON)
                .content(json))
            .andExpect(status().isBadRequest());
    }
}
4

@DataJpaTest

Loads only the JPA layer, auto-configures an in-memory DB, and rolls back each test; ideal for testing repository query correctness in isolation.

  • @DataJpaTest loads JPA layer only — no controllers, no services, no @Component beans.
  • Each test runs in a transaction that rolls back automatically — no teardown required.
  • H2 in-memory database is used by default; add @AutoConfigureTestDatabase(replace=NONE) to use a real DB.
  • TestEntityManager wraps EntityManager with helpers like persist(), flush(), find() useful for test setup.
  • Use Testcontainers for MySQL-specific features (JSON functions, window functions, Flyway migrations).
  • Import @EnableJpaAuditing configuration explicitly if it is not auto-applied in the slice.
Java — @DataJpaTest with TestEntityManager
@DataJpaTest   // loads only JPA slice; H2 replaces configured DB
class OrderRepositoryTest {

    @Autowired
    private TestEntityManager em;

    @Autowired
    private OrderRepository orderRepository;

    @Test
    void findByStatus_returnsPendingOrders() {
        // Arrange: persist test data via TestEntityManager
        Customer customer = em.persist(new Customer("john@example.com"));
        em.persist(new Order(customer, "PENDING", new BigDecimal("50.00")));
        em.persist(new Order(customer, "SHIPPED", new BigDecimal("30.00")));
        em.persist(new Order(customer, "PENDING", new BigDecimal("20.00")));
        em.flush();

        // Act
        List<Order> result = orderRepository.findByStatus("PENDING");

        // Assert
        assertThat(result).hasSize(2)
            .extracting(Order::getStatus)
            .containsOnly("PENDING");
    }

    @Test
    void findTopSpenders_returnsCustomersSortedByRevenue() {
        // Test a native query with aggregation
        // ...
        List<CustomerRevenue> top = orderRepository.findTopSpenders(
            PageRequest.of(0, 5));
        assertThat(top).isSortedAccordingTo(
            Comparator.comparing(CustomerRevenue::getTotalRevenue).reversed());
    }
}
5

Testcontainers with Spring Boot

Testcontainers spin up real Docker containers (Postgres, Kafka, Redis) for integration tests; the @Testcontainers + @Container annotations manage lifecycle.

  • Testcontainers starts real Docker containers for integration tests — no fake in-memory DBs
  • @ServiceConnection (Boot 3.1+) auto-configures datasource URL / broker address from the container
  • Declare containers as static fields so they start once per test class, not per test method
  • @ImportTestcontainers shares a container configuration class across multiple test classes
  • TESTCONTAINERS_REUSE_ENABLE=true skips restart between runs — speeds up local TDD
  • Use @DynamicPropertySource for pre-3.1 Spring Boot to feed container URLs to the context
Spring Boot 3.1 — @ServiceConnection with Postgres + Kafka
@SpringBootTest
@Testcontainers
class OrderServiceIntegrationTest {

    @Container
    @ServiceConnection               // auto-configures spring.datasource.url from the container
    static PostgreSQLContainer<?> postgres =
        new PostgreSQLContainer<>("postgres:16");

    @Container
    @ServiceConnection               // auto-configures spring.kafka.bootstrap-servers
    static KafkaContainer kafka =
        new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.6.0"));

    @Autowired OrderService orderService;
    @Autowired OrderRepository orderRepo;

    @Test
    void shouldPersistOrder() {
        Order saved = orderService.place(new CreateOrderRequest("SKU-1", 2));
        assertThat(orderRepo.findById(saved.getId())).isPresent();
    }
}
Learn this free with Aria, your AI tutor → AiCanCode.org/learn/spring-boot