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
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1@WebMvcTest loads just the web layer so tests stay fast and focused on request handling.
- 2Mocking the service with @MockBean lets each test pin down exactly what the controller receives.
- 3MockMvc lets you assert status codes, headers, and JSON fields without a running server.
Related explainers
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
java
package com.acme.billing.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties;
Feature-flagged beans with Spring @ConditionalOnProperty
feature-flags
conditional-beans
strategy-pattern
Intermediate
5 steps
java
public static Map<String, String> parseCookieHeader(String header) { Map<String, String> cookies = new LinkedHashMap<>(); if (header == null || header.isBlank()) { return cookies;
Parsing an HTTP Cookie header in Java
string-parsing
http
url-decoding
Intermediate
6 steps
java
public class TimedSocketReader { private static final int READ_TIMEOUT_MS = 5_000; private static final int CONNECT_TIMEOUT_MS = 3_000;
Reading a socket with connect and read timeouts
sockets
timeouts
io
Intermediate
8 steps
java
public final class EncodingDetector { public enum Encoding { UTF_8, UTF_16LE, UTF_16BE, UTF_32LE, UTF_32BE, ASCII, UNKNOWN
Detecting text encoding from raw bytes in Java
byte-manipulation
encoding-detection
bitwise-operations
Intermediate
8 steps
go
package httputil import ( "net"
Safely extracting the real client IP in Go
security
http
ip-spoofing
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/slice-testing-a-controller-with-webmvctest-in-spring-explained-java-bcf0/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.