Careeroza
@WebMvcTest and MockMvc
Testing the Web Layer
@WebMvcTest starts only the MVC part (controllers, advice, validation, Jackson). The service is replaced by a Mockito mock with @MockitoBean. MockMvc sends fake HTTP requests without a real server.
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
@WebMvcTest(ProductController.class)
class ProductControllerTest {
@Autowired MockMvc mockMvc;
@MockitoBean ProductService service; // Spring Boot 3.4+; older versions: @MockBean
@Test
void getReturnsProduct() throws Exception {
given(service.get(1L)).willReturn(new ProductResponse(1L, "ELE-1001", "Wireless Mouse",
"2.4 GHz", new BigDecimal("799.00"), 120, "Electronics", true));
mockMvc.perform(get("/api/products/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Wireless Mouse"))
.andExpect(jsonPath("$.price").value(799.00));
}
@Test
void getUnknownReturns404Problem() throws Exception {
given(service.get(42L)).willThrow(new ResourceNotFoundException("Product", 42L));
mockMvc.perform(get("/api/products/42"))
.andExpect(status().isNotFound())
.andExpect(content().contentType("application/problem+json"))
.andExpect(jsonPath("$.errorCode").value("NOT_FOUND"));
}
@Test
void createValidatesBody() throws Exception {
mockMvc.perform(post("/api/products")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"sku":"bad","name":"","price":-1,"stock":1,"category":"Electronics"}
"""))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errors.name").value("must not be blank"))
.andExpect(jsonPath("$.errors.sku").value("must look like ABC-1234"));
}
}Reading a Failure
Example
When a test fails, MockMvc tells you exactly what differed:
./mvnw test -Dtest=ProductControllerTestExample output
[ERROR] ProductControllerTest.getUnknownReturns404Problem:41 Status expected:<404> but was:<500> [INFO] Tests run: 3, Failures: 1, Errors: 0, Skipped: 0 [INFO] BUILD FAILURE
Here the mock threw an exception that no specific handler maps, so the catch-all Exception handler answered 500. @WebMvcTest does load @RestControllerAdvice beans, so check that the mock throws the exact exception type your handler expects.
Tip: Add .andDo(print()) to a perform(...) chain to print the full request and response while debugging.