Aquí hemos llegado a las pruebas de controladores. Los controladores, como sabes, se encargan de procesar peticiones HTTP y de pasar datos entre el cliente y la lógica de negocio de la aplicación. Todos quieren que sus controladores funcionen a la perfección, pero alguien tiene que comprobarlo. Spoiler: ese alguien serás tú. Por suerte, tenemos una herramienta potente — MockMvc.
¿Para qué probar controladores? Pues, primero, las pruebas de controladores te permiten tener la seguridad de que tus endpoints funcionan (y no solo en tu navegador).
Además, los controladores suelen ser el primer punto de la aplicación al que se dirige la ira de los usuarios cuando hay errores. Por ejemplo, ¿qué hará un usuario si una petición a la URI /api/users devuelve 500 Internal Server Error? Seguro que culpará a tu código (y, quizá, a ti personalmente). Así que, si tu código funciona, estás cubierto.
¿Qué es MockMvc?
MockMvc es una herramienta proporcionada por Spring Test que permite probar el comportamiento de aplicaciones web sin necesidad de desplegar un servidor real. Simula el procesamiento de peticiones HTTP y permite verificar las respuestas, los headers, los estados e incluso los errores.
MockMvc permite enviar peticiones HTTP de prueba a tus controladores y comprobar cómo responden. Por ejemplo, puedes enviar un GET a /api/users y verificar que el estado sea 200 y que el cuerpo contenga los datos esperados.
Aquí tienes un pequeño ejemplo de interacción con MockMvc:
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(content().json("[{\"id\":1,\"name\":\"John Doe\"}]"));
Preparación para las pruebas
Antes de escribir tests, asegurémonos de que tenemos todo lo necesario:
- Controlador: escribiremos un controlador de ejemplo que vamos a testear.
- Dependencias: añade Spring Boot Test, JUnit y Mockito para el trabajo.
- Configuración de MockMvc: configuraremos MockMvc para los tests.
Paso 1: Ejemplo de controlador para testear
Supongamos que tenemos un controlador para trabajar con usuarios:
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public List<User> getAllUsers() {
return userService.findAll();
}
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
User createdUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}
}
El controlador contiene dos endpoints:
GET /api/users— devuelve la lista de usuarios.POST /api/users— añade un usuario nuevo.
Paso 2: Configurar dependencias en pom.xml
Añadimos las dependencias necesarias para testing:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
Paso 3: Escribir tests para el controlador
Ahora creamos la clase de test para UserController.
Importamos las clases necesarias
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
Configuramos la clase de tests
@WebMvcTest(UserController.class)
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
// Aquí escribiremos los tests
}
Paso 4: Testear GET /api/users
Escribamos un test para comprobar que GET /api/users devuelve la lista correcta de usuarios.
@Test
public void shouldReturnListOfUsers() throws Exception {
// Creamos los datos de prueba
List<User> users = List.of(new User(1L, "John Doe"), new User(2L, "Jane Doe"));
// Configuramos el comportamiento del mock
when(userService.findAll()).thenReturn(users);
// Enviamos la petición GET y comprobamos el resultado
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.size()").value(users.size()))
.andExpect(jsonPath("$[0].name").value("John Doe"))
.andExpect(jsonPath("$[1].name").value("Jane Doe"));
}
Qué pasa aquí:
- Creamos la lista de usuarios para el test.
- Configuramos el mock
userServicepara que devuelva esa lista cuando se llame afindAll(). - Hacemos una petición GET a
/api/users. - Comprobamos:
- Estado de la respuesta (200 OK).
- El tamaño de la lista en la respuesta JSON.
- El valor del campo
namede los usuarios.
Paso 5: Testear POST /api/users
Probamos que POST /api/users crea un nuevo usuario.
@Test
public void shouldCreateNewUser() throws Exception {
// Creamos el usuario de prueba
User newUser = new User(null, "John Doe");
User savedUser = new User(1L, "John Doe");
// Configuramos el comportamiento del mock
when(userService.save(any(User.class))).thenReturn(savedUser);
// Enviamos la petición POST y comprobamos el resultado
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\":\"John Doe\"}"))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.name").value("John Doe"));
}
Aquí:
- Enviamos una petición POST con un objeto JSON.
- Comprobamos que:
- El estado de la respuesta —
201 Created - La respuesta contiene el ID y el nombre del nuevo usuario.
- El estado de la respuesta —
Consejos útiles
- No te olvides de los edge cases: prueba no solo escenarios positivos, sino también los negativos. Por ejemplo, qué pasa si envías datos incorrectos.
- Usa métodos útiles: MockMvc ofrece muchos métodos prácticos, como
jsonPath(),header()y demás. - Límpialo todo: que tus tests no dependan del estado de tests anteriores. Cada test debe ser independiente.
¿Y ahora qué?
Ahora sabes testear REST-controladores usando MockMvc. Esto no solo es útil para asegurar la calidad, sino que también queda muy bien en el currículum. En la siguiente clase nos centraremos en testear servicios y repositorios. Mientras tanto, coge estos conocimientos y ponte a testear tus controladores!
GO TO FULL VERSION