Mock es un objeto sustituto que imita el comportamiento de un componente real y permite verificar las interacciones con él. A diferencia de Stub, que simplemente devuelve un valor predeterminado, Mock registra el hecho de la invocación del método, los argumentos pasados y el número de llamadas. Según Mockito (2024), Mock es el tipo de Test Double más popular en proyectos Java y Kotlin, utilizado en más del 70% de las pruebas unitarias de aplicaciones móviles.
Puntos clave
Mock es un objeto creado por un framework de mocking (Mockito, MockK, EasyMock) que simula una interfaz o clase y registra todas las llamadas a sus métodos. El desarrollador establece expectativas: el método X se llamará con los argumentos Y y devolverá Z. Después de ejecutar la prueba, Mock verifica que las expectativas coincidieron con las llamadas reales.
El término proviene de la metáfora teatral de Test Doubles: un Mock es un “impostor” que no solo está en el escenario (como un Dummy) sino que interpreta un rol y verifica si la interacción con él fue correcta. Si el código bajo prueba no llamó al método que Mock esperaba, o lo llamó con argumentos incorrectos — la prueba falla con un mensaje de expectativa violada.
Un Mock se crea a través de la fábrica del framework: mockk<MyInterface>() o Mockito.mock(MyClass.java). El framework genera un objeto proxy que intercepta todas las llamadas a métodos. Cada llamada se compara con expectativas predefinidas. Si la llamada coincide con una expectativa — se devuelve el valor especificado. Si no — Mock devuelve un valor por defecto o lanza una excepción, según la configuración.
Mock es esencial cuando el código bajo prueba interactúa con componentes que tienen efectos secundarios: enviar datos a un servidor, escribir en una base de datos, registrar, analytics, navegación, mostrar diálogos del sistema. Sin Mocks, estas interacciones no se pueden verificar sin ejecutar infraestructura real. Según el Google Testing Blog, Mock es la única forma de verificar que una aplicación realmente envió un evento de analytics sin levantar un servidor de prueba.
La diferencia entre Mock y Stub es uno de los temas más debatidos en las pruebas. Ambos tipos reemplazan una dependencia real, pero de formas fundamentalmente diferentes.
| Criterio | Mock | Stub |
|---|---|---|
| Pregunta principal | ¿Se llamó al método? | ¿Qué resultado se devolvió? |
| Verificación | Comportamiento (verify) | Estado (assert) |
| Devolución de datos | Opcional | Obligatoria |
| Ejemplo | verify(analytics).logEvent(“click”) | assertEquals(5, repository.getCount()) |
| Cuándo usar | Efectos secundarios | Devolución de datos |
Una prueba simple para decidir: pregúntate “si elimino esta línea de código, ¿fallará la prueba?” Si la prueba verifica un valor de retorno — necesitas un Stub (verificación basada en assert). Si la prueba verifica que el código llamó a un método con los argumentos correctos — necesitas un Mock (verificación basada en verify). Esta dicotomía sigue el patrón Command-Query Separation: los métodos que cambian el estado (commands) necesitan Mocks; los métodos que devuelven datos (queries) necesitan Stubs.
Elegir entre Mockito y MockK es una de las primeras decisiones al configurar el stack de pruebas para un proyecto Android en Kotlin. Ambas bibliotecas cumplen el mismo propósito, pero con diferentes enfoques hacia las características específicas de Kotlin.
Mockito es el estándar de facto para proyectos Java. La versión 5.x soporta mocking para clases finales, métodos estáticos y constructores gracias al MockMaker incorporado. Para proyectos Kotlin, Mockito requiere configuración adicional: extensiones mockito-kotlin para una sintaxis mejorada, mockito-inline para clases finales. Mockito no soporta corrutinas de Kotlin ni funciones suspend sin adaptadores adicionales.
MockK fue creado específicamente para Kotlin. Soporta de forma nativa corrutinas (coEvery, coVerify), clases selladas, clases de datos, singletons de objeto y funciones de extensión. La sintaxis de MockK usa DSL con bloques lambda, lo que se ve natural en código Kotlin. MockK también soporta mocking de propiedades sin configuración adicional — esto es importante para proyectos Android que usan LiveData, StateFlow y Delegates.
// Mockito + mockito-kotlin
val repository = mock<UserRepository>()
whenever(repository.getUser(1)).thenReturn(user)
// MockK
val repository = mockk<UserRepository>()
every { repository.getUser(1) } returns user
Los benchmarks (JVM Benchmark, 2024) muestran que MockK crea objetos mock un 15–20% más rápido que Mockito para proyectos Kotlin gracias al trabajo directo con el bytecode de Kotlin en lugar de Java Reflections. Para proyectos con miles de pruebas unitarias, la diferencia en la velocidad de compilación puede ser notable: MockK ahorra 30–60 segundos en una ejecución completa de pruebas en proyectos grandes.
Examinemos tres escenarios: probar un ViewModel con dependencias Mock, probar un UseCase verificando llamadas API y probar corrutinas con coVerify.
class ProfileViewModelTest {
private val analytics = mockk<AnalyticsService>()
private val repo = mockk<UserRepository>()
private val vm = ProfileViewModel(repo, analytics)
fun `profile opened logs analytics event`() {
every { analytics.logEvent("profile_opened") } returns Unit
vm.onViewCreated()
verify { analytics.logEvent("profile_opened") }
}
}
class SendMessageUseCaseTest {
private val api = mockk<MessagingApi>()
private val useCase = SendMessageUseCase(api)
fun `send message with correct payload`() = runTest {
val message = Message(text = "Hello", userId = 42)
coEvery { api.sendMessage(any()) } returns MessageResult.Sent("msg_1")
val result = useCase.execute(message)
coVerify {
api.sendMessage(match {
it.text == "Hello" && it.userId == 42
})
}
assertTrue(result is MessageResult.Sent)
}
}
class OrderUseCaseTest {
private val api = mockk<OrderApi>()
private val useCase = OrderUseCase(api)
private val slot = slot<OrderRequest>()
fun `order request contains correct items`() = runTest {
coEvery { api.placeOrder(capture(slot)) } returns OrderResult.Placed("order_1")
useCase.execute(listOf("item_a", "item_b"))
assertEquals(2, slot.captured.items.size)
assertEquals("item_a", slot.captured.items[0])
}
}
El uso efectivo de Mock en el desarrollo móvil requiere disciplina. Violar estas reglas convierte las pruebas en obstáculos frágiles que se rompen con cada refactorización.
Una regla estricta: los Mocks solo deben crearse para dependencias que cruzan el límite de la aplicación: clientes API, bases de datos, sistema de archivos, servicios del sistema (LocationManager, BluetoothAdapter, Camera). Las clases internas de la aplicación — entidades de dominio, Value Objects, utilidades simples — no deben reemplazarse con Mocks. Su comportamiento se prueba a través de objetos reales.
Cada prueba debe contener exactamente una verificación lógica — ya sea verify (para Mock) o assert (para Stub). No mezcles la verificación de estado y comportamiento en una misma prueba. Si necesitas verificar tanto una llamada API como su resultado — crea dos pruebas separadas con nombres diferentes. Esta regla, conocida como “un assert por prueba”, se remonta a las recomendaciones de Kent Beck (2002).
Más allá del mocking básico, existen técnicas avanzadas que resuelven tareas específicas en el desarrollo móvil: probar la concurrencia, verificar el estado de Flow y el mocking parcial de objetos reales.
Spy (o mock parcial) permite crear un objeto que delega llamadas a la implementación real pero permite sobrescribir métodos individuales. En MockK, spyk se crea basado en una instancia de clase real: val repo = spyk(InMemoryUserRepository()). Las llamadas con expectativas definidas mediante every pasan por el Mock; el resto pasan por el objeto real. Spy es especialmente útil para probar código heredado donde la inyección de dependencias aún no se ha implementado y solo necesitas sobrescribir un método.
En proyectos Android modernos con Jetpack Compose, el ViewModel expone el estado a través de StateFlow. MockK permite mockear dependencias Flow, y la biblioteca Turbine simplifica la verificación de emisiones. El patrón clásico: MockK para un UseCase que devuelve un Flow, Turbine para verificar las emisiones del ViewModel. Este stack es recomendado por la documentación de Android Testing (Google, 2024) para proyectos con Kotlin Coroutines.
class SearchViewModelTest {
private val searchUseCase = mockk<SearchUseCase>()
private val vm = SearchViewModel(searchUseCase)
fun `search emits results`() = runTest {
coEvery { searchUseCase.search("android") } returns
flowOf(SearchResult.Success(listOf(Item("Android TDD"))))
vm.search("android")
vm.state.test {
val state = awaitItem()
assertTrue(state.items.isNotEmpty())
cancelAndIgnoreRemainingEvents()
}
}
}
Preguntas frecuentes
Mock es un concepto, un tipo de Test Double que verifica el comportamiento. Mockito es una biblioteca para crear objetos Mock en Java y Android. Otras bibliotecas: MockK (Kotlin), EasyMock (Java), Cuckoo (iOS).
Para probar funciones suspend con Mock, usa MockK (coEvery / coVerify) o Mockito con mockito-kotlin. MockK soporta corrutinas de forma nativa: coEvery define el comportamiento de una función suspend, coVerify verifica su llamada dentro de una corrutina. Todas las llamadas suspend deben ejecutarse dentro de runTest (kotlinx-coroutines-test).
Sí. En MockK, usa returnsMany: every { api.getData() } returnsMany listOf(response1, response2). En Mockito — una cadena de thenReturn(value1).thenReturn(value2). Esto es útil para probar el comportamiento con llamadas secuenciales que devuelven diferentes respuestas.
En MockK, usa la anotación @MockK con relaxed = true y llama a clearMocks(mock) en el método @After. En Mockito — Mockito.reset(mock). La mejor práctica: crear un nuevo Mock para cada prueba mediante @Before para eliminar la interferencia entre pruebas.
MockK funciona correctamente con clases selladas: every { useCase() } returns Result.Success(data). Mockito no soporta clases selladas directamente, requiriendo soluciones alternativas. Esta es una razón por la que se recomienda MockK para proyectos Kotlin en lugar de Mockito.
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