CodeGym /Cursos /Módulo 5. Spring /Lección 138: Introducción a MockMvc para probar controlad...

Lección 138: Introducción a MockMvc para probar controladores MVC

Módulo 5. Spring
Nivel 9 , Lección 7
Disponible

Cuando se trata de Spring MVC y de nuestros controladores REST, es importante asegurarse de que la aplicación maneje correctamente todas las solicitudes. Imagínate que tu controlador tiene que hacer una tarea compleja, como recibir una petición de pedido de pizza, pero en vez de eso te envía khachapuri. MockMvc permite probar esos escenarios (bueno, no sobre pizza, sino sobre el manejo correcto de las solicitudes).

MockMvc te ayuda a:

  1. Comprobar que las rutas sean correctas (por ejemplo, GET /api/orders/{id}).
  2. Asegurarte de que los endpoints devuelvan los estados HTTP correctos (200, 404).
  3. Verificar que el cuerpo de la respuesta contenga exactamente lo que esperas (JSON, XML, etc.).
  4. Detectar bugs antes de que algún tester de QA los encuentre y te deje en evidencia.

MockMvc forma parte de spring-test — la librería que viene con Spring Framework. Es decir, no tienes que instalar nada adicional si ya trabajas con Spring en tu proyecto.


Configuración de MockMvc

Para empezar, veamos cómo preparar el entorno. Puedes usar la anotación @AutoConfigureMockMvc, que configura MockMvc automáticamente para tu aplicación.

Ejemplo de configuración:


@SpringBootTest
@AutoConfigureMockMvc
public class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc; // MockMvc se configurará automáticamente

    // Aquí van los tests
}

Si te sientes con ganas de hacerlo todo a mano, así es como puedes configurarlo:


@BeforeEach
void setUp() {
    mockMvc = MockMvcBuilders.standaloneSetup(new OrderController()).build();
}

Escribir un test básico con MockMvc

Probemos el controlador más simple. Supongamos que tenemos un controlador que devuelve un mensaje de bienvenida.


@RestController
@RequestMapping("/api/hello")
public class HelloController {

    @GetMapping
    public ResponseEntity<String> sayHello() {
        return ResponseEntity.ok("¡Hola, mundo!");
    }
}

Ahora lo probamos:


@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testSayHello() throws Exception {
        mockMvc.perform(get("/api/hello")) // Simulamos una petición GET
            .andExpect(status().isOk())    // Comprobamos que el estado de la respuesta sea 200
            .andExpect(content().string("¡Hola, mundo!")); // Comprobamos que el cuerpo de la respuesta contenga "¡Hola, mundo!"
    }
}

Veamos qué ocurre aquí:

  1. mockMvc.perform(get("/api/hello")) — simulamos una petición HTTP GET.
  2. andExpect(status().isOk()) — comprobamos que se devuelve el estado HTTP 200.
  3. andExpect(content().string("¡Hola, mundo!")) — garantizamos que el cuerpo de la respuesta contiene la cadena esperada.

Comprobación de respuestas JSON

La mayoría de tus controladores probablemente devolverán respuestas en formato JSON. MockMvc facilita mucho el trabajo con JSON.

Ejemplo de controlador:


@RestController
@RequestMapping("/api/orders")
public class OrderController {

    @GetMapping("/{id}")
    public ResponseEntity<OrderDTO> getOrder(@PathVariable Long id) {
        OrderDTO order = new OrderDTO(id, "Pizza", 2); // Devolvemos un objeto 'stub'
        return ResponseEntity.ok(order);
    }
}

Ejemplo de la clase DTO:


public class OrderDTO {
    private Long id;
    private String name;
    private int quantity;

    // Constructores, getters y setters
}

Ahora escribimos el test:


@SpringBootTest
@AutoConfigureMockMvc
public class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testGetOrder() throws Exception {
        mockMvc.perform(get("/api/orders/1")) // Simulamos una petición GET
            .andExpect(status().isOk()) // Comprobamos el estado 200 OK
            .andExpect(jsonPath("$.id").value(1)) // Comprobamos el campo "id"
            .andExpect(jsonPath("$.name").value("Pizza")) // Comprobamos el campo "name"
            .andExpect(jsonPath("$.quantity").value(2)); // Comprobamos el campo "quantity"
    }
}

Lo clave aquí es jsonPath. Este método ayuda a extraer valores de objetos JSON y verificarlos. Por ejemplo:

  • $.id — es la ruta al campo id en el objeto raíz.

Comprobación de cabeceras HTTP

Si tu controlador añade cabeceras especiales en la respuesta, MockMvc también te echa una mano aquí.

Ejemplo de controlador:


@RestController
@RequestMapping("/api/headers")
public class HeaderController {

    @GetMapping
    public ResponseEntity<String> getHeader() {
        return ResponseEntity.ok()
            .header("X-Custom-Header", "HeaderValue")
            .body("Respuesta con cabecera");
    }
}

Test:


@SpringBootTest
@AutoConfigureMockMvc
public class HeaderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testCustomHeader() throws Exception {
        mockMvc.perform(get("/api/headers"))
            .andExpect(status().isOk()) // Comprobamos el estado 200
            .andExpect(header().string("X-Custom-Header", "HeaderValue")); // Comprobamos la cabecera
    }
}

Manejo de peticiones POST

A veces necesitas probar endpoints que reciben datos del cliente. Imagina que tienes un controlador que maneja la creación de nuevos pedidos.

Ejemplo de controlador:


@RestController
@RequestMapping("/api/orders")
public class OrderController {

    @PostMapping
    public ResponseEntity<OrderDTO> createOrder(@RequestBody OrderDTO order) {
        order.setId(100L); // Establecemos el ID del pedido creado
        return ResponseEntity.status(HttpStatus.CREATED).body(order);
    }
}

Test:


@SpringBootTest
@AutoConfigureMockMvc
public class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testCreateOrder() throws Exception {
        String orderJson = "{ \"name\": \"Pizza\", \"quantity\": 1 }";

        mockMvc.perform(post("/api/orders")
                .contentType(MediaType.APPLICATION_JSON) // Indicamos el tipo de contenido
                .content(orderJson)) // Enviamos el cuerpo de la petición
            .andExpect(status().isCreated()) // Comprobamos el estado 201 Created
            .andExpect(jsonPath("$.id").value(100)) // Comprobamos que el ID esté establecido
            .andExpect(jsonPath("$.name").value("Pizza")) // Comprobamos el nombre
            .andExpect(jsonPath("$.quantity").value(1)); // Comprobamos la cantidad
    }
}

Consejos y errores típicos

Cuando uses MockMvc, asegúrate de que:

  1. Indicas correctamente las rutas. A menudo se olvida poner el @RequestMapping base en el controlador.
  2. Las cabeceras y los tipos de contenido coinciden con lo que espera tu endpoint. Por ejemplo, si envías JSON, no olvides contentType(MediaType.APPLICATION_JSON).

Si MockMvc lanza un error diciendo que no puede encontrar el controlador, comprueba si tienes la anotación @SpringBootTest configurada y si tu controlador está en el contexto de la aplicación.


MockMvc es tu primer paso hacia controladores perfectamente testeados. En las siguientes lecciones profundizaremos en tests más complejos y veremos la integración con bases de datos reales.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION