MockMvc y @WebMvcTest a Fondo
@WebMvcTest arranca solo la capa web y MockMvc simula peticiones HTTP sin servidor real: comprueba rutas, validación, códigos de estado, cabeceras y el JSON de respuesta con jsonPath. Los servicios se sustituyen con @MockitoBean.
En una línea mvc.perform(post("/tareas").contentType(APPLICATION_JSON).content("{}")).andExpect(status().isBadRequest()).andExpect(jsonPath("$.title").exists());
@WebMvcTest(TareaController.class)
class TareaControllerTest {
@Autowired MockMvc mvc;
@MockitoBean TareaService servicio;
@Test
void crear_devuelve_201_con_location() throws Exception {
given(servicio.crear(any())).willReturn(new TareaDto(42L, "Revisar PR", Estado.PENDIENTE));
mvc.perform(post("/tareas")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"titulo": "Revisar PR"}
"""))
.andExpect(status().isCreated())
.andExpect(header().string("Location", endsWith("/tareas/42")))
.andExpect(jsonPath("$.estado").value("PENDIENTE"));
}
@Test
void crear_sin_titulo_devuelve_400_con_problem_detail() throws Exception {
mvc.perform(post("/tareas")
.contentType(MediaType.APPLICATION_JSON)
.content("{}"))
.andExpect(status().isBadRequest())
.andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON))
.andExpect(jsonPath("$.status").value(400));
verifyNoInteractions(servicio);
}
}
Cómo funciona por dentro
@WebMvcTest(TareaController.class) crea un contexto de Spring reducido: el controlador indicado, los @ControllerAdvice, los convertidores de Jackson, la validación, los filtros y la seguridad web si está configurada. No crea servicios ni repositorios, así que los que necesite el controlador se aportan con @MockitoBean. Arranca en uno o dos segundos y cada test tarda milisegundos.
MockMvc ejecuta la petición por toda la pila de Spring MVC sin abrir un puerto: el DispatcherServlet resuelve la ruta, deserializa el cuerpo, valida, llama al controlador y serializa la respuesta. Con jsonPath compruebas campos concretos del JSON, y con header(), las cabeceras. Desde Spring Framework 6.2 existe también MockMvcTester, con aserciones al estilo AssertJ.
Qué probar aquí: códigos de estado, validación de la entrada, formato de los errores (ProblemDetail), cabeceras como Location, la serialización de fechas y enums, y las reglas de seguridad de cada endpoint. Qué no: la lógica de negocio (va en tests unitarios del servicio) ni el acceso a datos.
ProblemDetail y que crear devuelve 201 con Location.
@MockitoBean sustituye a @MockBean, que queda obsoleto.
Se conecta con @MockitoBeanProblemDetailBean Validation