java 59 lines · 8 steps

Slice testing a controller with @WebMvcTest in Spring

A focused web-layer test that loads only the controller, mocks the service, and asserts HTTP behavior end to end.

Explained by highlit
1@WebMvcTest(OrderController.class)
2class OrderControllerTest {
3 
4 @Autowired
5 private MockMvc mockMvc;
6 
7 @Autowired
8 private ObjectMapper objectMapper;
9 
10 @MockBean
11 private OrderService orderService;
12 
13 @Test
14 void returnsOrderWhenFound() throws Exception {
15 var order = new OrderResponse(42L, "SHIPPED", new BigDecimal("129.99"));
16 when(orderService.findById(42L)).thenReturn(order);
17 
18 mockMvc.perform(get("/api/orders/{id}", 42L))
19 .andExpect(status().isOk())
20 .andExpect(jsonPath("$.id").value(42))
21 .andExpect(jsonPath("$.status").value("SHIPPED"))
22 .andExpect(jsonPath("$.total").value(129.99));
23 }
24 
25 @Test
26 void returns404WhenMissing() throws Exception {
27 when(orderService.findById(99L)).thenThrow(new OrderNotFoundException(99L));
28 
29 mockMvc.perform(get("/api/orders/{id}", 99L))
30 .andExpect(status().isNotFound())
31 .andExpect(jsonPath("$.message").value("Order 99 not found"));
32 }
33 
34 @Test
35 void createsOrderFromValidPayload() throws Exception {
36 var request = new CreateOrderRequest("ACME-7", 3);
37 when(orderService.create(any(CreateOrderRequest.class)))
38 .thenReturn(new OrderResponse(7L, "PENDING", new BigDecimal("59.97")));
39 
40 mockMvc.perform(post("/api/orders")
41 .contentType(MediaType.APPLICATION_JSON)
42 .content(objectMapper.writeValueAsString(request)))
43 .andExpect(status().isCreated())
44 .andExpect(header().string("Location", "/api/orders/7"))
45 .andExpect(jsonPath("$.status").value("PENDING"));
46 }
47 
48 @Test
49 void rejectsInvalidPayload() throws Exception {
50 var request = new CreateOrderRequest("", 0);
51 
52 mockMvc.perform(post("/api/orders")
53 .contentType(MediaType.APPLICATION_JSON)
54 .content(objectMapper.writeValueAsString(request)))
55 .andExpect(status().isBadRequest());
56 
57 verifyNoInteractions(orderService);
58 }
59}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1@WebMvcTest loads just the web layer so tests stay fast and focused on request handling.
  2. 2Mocking the service with @MockBean lets each test pin down exactly what the controller receives.
  3. 3MockMvc lets you assert status codes, headers, and JSON fields without a running server.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Slice testing a controller with @WebMvcTest in Spring — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code