Mockito es un framework de código abierto para crear objetos mock en pruebas unitarias de Java y Kotlin, que permite aislar el código bajo prueba de las dependencias externas. Con su ayuda, el desarrollador reemplaza repositorios reales, clientes API y bases de datos con stubs controlados que tienen un comportamiento predefinido. Según Mockito.org, la biblioteca se utiliza en más del 60% de los proyectos Java que realizan pruebas unitarias.
Puntos clave
Mockito es una biblioteca de código abierto para crear objetos mock (stubs) en pruebas unitarias para Java, Kotlin y otros lenguajes JVM. A diferencia de JUnit, que se encarga de ejecutar las pruebas, Mockito resuelve el problema del aislamiento — reemplaza las dependencias reales de la clase bajo prueba con objetos predecibles.
Sin mocks, probar un método que accede a una base de datos o API externa requiere configurar un entorno real — desplegar una base de datos, iniciar un servidor. Mockito reemplaza estas dependencias con objetos de comportamiento fijo: el método repository.findById(1) siempre devuelve un objeto User dado sin acceder a la base de datos.
La arquitectura de Mockito se basa en el patrón Proxy (para interfaces y clases). La biblioteca genera una subclase o proxy para el tipo especificado e intercepta todas las llamadas a métodos, devolviendo valores por defecto o valores establecidos mediante when().thenReturn().
El principio de funcionamiento de Mockito se basa en tres operaciones básicas: creación del mock, configuración del comportamiento (stubbing) y verificación de llamadas (verification). Cada operación utiliza métodos estáticos de la clase org.mockito.Mockito — la clase más descargada en el ecosistema Java según las estadísticas de Maven Central. Todas las llamadas a métodos del mock se registran en memoria, lo que permite verificarlas posteriormente mediante verify.
Una prueba típica con Mockito consta de tres fases: Arrange — creación de mocks y configuración de stubs mediante when().thenReturn(), Act — llamada al método bajo prueba, Assert — comprobación del resultado mediante assertEquals y verify(mock). Este enfoque se denomina AAA (Arrange-Act-Assert).
Veamos una prueba sencilla donde Mockito reemplaza un repositorio de usuarios. El método when().thenReturn() configura el mock para que la llamada a findById devuelva un objeto User previamente preparado.
// Creando un mock de repositorio
UserRepository mockRepo = mock(UserRepository.class);
// Configurando el comportamiento: findById(1) devuelve un usuario
when(mockRepo.findById(1)).thenReturn(new User("Alice"));
// Verificando que el método realmente fue llamado
User result = mockRepo.findById(1);
assertEquals("Alice", result.getName());
verify(mockRepo).findById(1);
Mockito proporciona dos formas de crear mocks: el método estático mock(Class) y la anotación @Mock con inicialización mediante MockitoAnnotations.openMocks(). El primer enfoque es compacto para uno o dos mocks, el segundo es conveniente cuando hay muchas dependencias — las anotaciones reducen el código boilerplate.
El método mock() recibe una clase y devuelve un objeto stub que puede configurarse mediante when().thenReturn(). Todos los métodos no configurados devuelven valores por defecto: 0 para números, false para boolean, null para objetos.
ApiClient apiClient = mock(ApiClient.class);
Database database = mock(Database.class);
La anotación @Mock combinada con @ExtendWith(MockitoExtension.class) crea automáticamente mocks para todos los campos de la clase de prueba. MockitoExtension se encarga de la inicialización antes de cada prueba.
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void getUserShouldReturnUserFromRepo() {
when(userRepository.findById(1)).thenReturn(new User("Alice"));
User result = userService.getUser(1);
assertEquals("Alice", result.getName());
}
}
Stubbing es el proceso de definir lo que debe devolver un método del mock cuando se llama con argumentos específicos. La sintaxis básica: when(mock.method(args)).thenReturn(value). Para diferentes escenarios, Mockito ofrece varias variantes de métodos then.
| Método | Propósito |
|---|---|
| thenReturn(value) | Siempre devuelve el valor especificado |
| thenThrow(exception) | Lanza una excepción al ser llamado |
| thenAnswer(answer) | Calcula el valor de retorno dinámicamente |
| thenCallRealMethod() | Llama al método real (mock parcial) |
Cuando el valor de retorno depende de los argumentos de la llamada, se utiliza thenAnswer con una lambda. Esto es útil para simular el trabajo con datos reales — por ejemplo, generar un ID basado en el objeto recibido.
when(repository.save(any())).thenAnswer(invocation -> {
User user = invocation.getArgument(0);
user.setId(42);
return user;
});
Verify es una característica única de Mockito que las bibliotecas de objetos mock más antiguas (EasyMock, jMock) no proporcionan.
Verify hace que las pruebas sean más confiables porque comprueba no solo el valor de retorno sino también los efectos secundarios — llamadas a métodos que no devuelven resultado (métodos void). El método verify(mock).methodName(args) verifica si un método específico del mock fue llamado con los argumentos indicados. Esto permite probar no solo el resultado sino también el proceso — el hecho de acceder a la dependencia.
Por defecto, verify comprueba que el método fue llamado exactamente una vez. Si se necesita un número diferente, se utilizan times(n), atLeast(n), never() y otros modificadores de la clase Mockito.
// Verificación del número de llamadas
verify(repository, times(3)).save(any());
verify(repository, never()).delete(any());
verify(repository, atLeastOnce()).findById(1);
// Verificación del orden de las llamadas
InOrder inOrder = inOrder(repository);
inOrder.verify(repository).save(any());
inOrder.verify(repository).flush();
Cuando es necesario comprobar con qué objeto exacto se llamó a un método, se utiliza ArgumentCaptor. Captura el valor del argumento durante la llamada y permite verificar sus campos individualmente. ArgumentCaptor es especialmente útil cuando el código bajo prueba crea un objeto internamente y lo pasa a una dependencia — no se puede verificar ese objeto de otra manera.
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Alice", captor.getValue().getName());
@Mock y @InjectMocks son dos anotaciones clave de Mockito que reducen significativamente el código boilerplate. @Mock crea un mock para un campo, y @InjectMocks inyecta todos los mocks de la clase de prueba en el objeto bajo prueba mediante constructor, setter o campo.
El mecanismo de @InjectMocks intenta inyectar las dependencias en el siguiente orden: constructor con la mayor cantidad de argumentos, setter por tipo, campo privado. Si ninguno de estos métodos funciona, el objeto se queda con dependencias null y la prueba fallará con una NullPointerException.
Es importante entender: @InjectMocks no analiza los tipos de campo — sustituye cualquier mock que sea compatible por tipo. Si una clase tiene dos campos del mismo tipo, Mockito puede inyectar el mock incorrecto. En tales casos, se recomienda usar un constructor explícito con parámetros mock.
En el desarrollo Android, Mockito se utiliza junto con JUnit para probar ViewModel, Repository y UseCase. Dado que estas clases se ejecutan en la JVM sin el contexto de Android, Mockito reemplaza sus dependencias — Room DAO, Retrofit API, SharedPreferences — con stubs de comportamiento predecible.
Para agregar Mockito a un proyecto Android, basta con añadir la dependencia mockito-core o mockito-inline (esta última soporta el mock de clases finales y métodos estáticos). La versión 5.12.0 (2024) incluye soporte para Java 21 y una integración mejorada con JUnit 5.
// build.gradle.kts (module)
dependencies {
testImplementation("org.mockito:mockito-core:5.12.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
}
Anteriormente, para mockear métodos estáticos y constructores se requería PowerMock — una extensión que funcionaba mediante instrumentación de bytecode. A partir de Mockito 5.x con mockito-inline, esta capacidad está integrada directamente: mockStatic(ClassName.class) permite mockear métodos estáticos sin bibliotecas adicionales.
Un escenario típico: un ViewModel llama a un método del repositorio y transforma el resultado en un estado de UI. Mockito reemplaza el repositorio, y la prueba verifica que el ViewModel maneje correctamente tanto la respuesta exitosa como el error. Al usar la Clean Architecture, se crean mocks para cada capa: DataSource, Repository y UseCase — esto permite probar cada capa de forma aislada.
Preguntas frecuentes
Mockito es una biblioteca para Java y Kotlin que utiliza proxies y reflexión. MockK es una biblioteca Kotlin-first con soporte para corrutinas, funciones de extensión y clases finales sin configuración adicional.
A partir de Mockito 2.1, el mock de clases finales se soporta mediante opt-in. En la versión 5.x (mockito-inline), esto está activado por defecto. Basta con añadir la dependencia mockito-inline y usar el método estándar mock().
Un Spy es un mock parcial que por defecto llama a métodos reales pero permite sobrescribir algunos de ellos mediante when().thenReturn(). Spy es útil para probar código heredado cuando no se puede reescribir toda la clase.
thenReturn siempre devuelve el mismo valor, independientemente de los argumentos. thenAnswer calcula el valor de retorno basándose en la invocación — argumentos de la llamada, el propio mock y el estado. Para respuestas dinámicas, usa siempre thenAnswer.
Verify comprueba no solo el resultado sino también el proceso — el hecho de acceder a la dependencia. Esto es crítico para servicios que deben guardar datos o enviar notificaciones. Sin verify, la prueba no detectará que un método no llamó a save() o send().
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también