Configuración de Mockito en Proyectos Maven
Para integrar Mockito en un proyecto Spring Boot, incluye la siguiente dependencia en el archivo pom.xml:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.11.0</version>
<scope>test</scope>
</dependency>
Plantilla Básica para Pruebas
Ejemplo de una clase de prueba que utiliza anotaciones de Mockito para simular dependencias:
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
public class ProductoServiceTest {
@Mock
private ProductoRepositorio productoRepo;
@InjectMocks
private ProductoServiceImpl productoService;
@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
public void testObtenerProductoPorId() {
// Definir comportamiento simulado del repositorio
when(productoRepo.buscarPorId(10L))
.thenReturn(new Producto("Monitor", 299.99));
// Ejecutar el método bajo prueba
Producto resultado = productoService.obtenerDetalle(10L);
// Verificar resultados e interacciones
assertNotNull(resultado);
assertEquals("Monitor", resultado.getNombre());
verify(productoRepo, times(1)).buscarPorId(10L);
}
}
Operaciones Fundamentales de Mockito
Creación de Objetos Mock
Se pueden definir mocks mediante anotaciones o instancias manuales:
// Mediante anotación
@Mock
private MiServicio servicioMock;
// Creación programática
MiServicio mockManual = mock(MiServicio.class);
Stubbing de Métodos
Simula respuestas específicas para métodos dependientes:
// Retorno de valor predeterminado
when(mock.metodo()).thenReturn(valor);
// Simulación de excepciones
when(mock.metodo()).thenThrow(new RuntimeException());
// Respuestas secuenciales
when(mock.metodo())
.thenReturn(primerValor)
.thenReturn(segundoValor);
// Uso de matchers de parámetros
when(mock.metodo(anyInt(), startsWith("test"))).thenReturn(valor);
Verificación de Interacciones
Comprueba que los métodos mock se invocaron correctamente:
// Verificación básica de llamada
verify(mock).metodo();
// Conteo exacto de invocaciones
verify(mock, times(3)).metodo();
verify(mock, never()).metodo();
// Captura y validación de argumentos
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(mock).metodo(captor.capture());
assertEquals("esperado", captor.getValue());
Escenarios Avanzados
Métodos Void
Controla el comportamiento de métodos sin valor de retorno:
doThrow(new IllegalStateException())
.when(mock).metodoVoid();
doNothing().when(mock).metodoVoid();
Spy para Simulación Selectiva
Permite simular solo ciertos métodos de un objeto real:
List listaReal = new ArrayList();
List listaEspia = spy(listaReal);
// Mockear únicamente el método size
doReturn(50).when(listaEspia).size();
Verificación con Tiempo de Espera
Valida que un método sea llamado dentro de un intervalo específico:
verify(mock, timeout(150).atLeast(1)).metodo();
Recomendaciones de Uso
- Utiliza @InjectMocks para la inyección automática de dependencias mockeadas.
- Prefiere matchers de parámetros como any() o eq() en lugar de valores fijos para mayor flexibilidad.
- Diseña cada caso de prueba para validar un único comportamiento o flujo.
- Emplea la anotación @Captor para capturar argumentos en verificaciones complejas.
Ejemplo Integrado: Servicio de Citas Médicas
Implementación de pruebas para un servicio que gestiona citas médicas, con dependencias en repositorios y servicios externos.
public class CitaServiceTest {
@Mock
private MedicoRepositorio medicoRepo;
@Mock
private SistemaNotificaciones notificaciones;
@InjectMocks
private CitaServiceImpl citaService;
@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
public void deberiaAgendarCitaExitosamente() {
// Configurar comportamientos simulados
when(medicoRepo.estaDisponible("DR-123", "2023-11-15")).thenReturn(true);
when(notificaciones.enviarConfirmacion(anyString())).thenReturn(true);
// Ejecutar la lógica de negocio
Cita cita = new Cita("DR-123", "2023-11-15", "10:00");
ResultadoCita resultado = citaService.agendar(cita);
// Validar resultados y interacciones
assertTrue(resultado.isConfirmada());
verify(notificaciones).enviarConfirmacion(eq("DR-123"));
verify(medicoRepo).bloquearHorario("DR-123", "2023-11-15", "10:00");
}
}
Este caso ilustra cómo simular dependencias externas y verificar el flujo completo del servicio, asegurando tanto la lógica de negocio como las interacciones con componentes secundarios.