Mock — qué es, objetos mock y bibliotecas para pruebas

Autor: IT Sectr Publicado: 2026-04-10 Tiempo de lectura: 8 min

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 — un objeto que verifica la interacción: qué métodos se llamaron, con qué argumentos y cuántas veces
  • Mockito — la biblioteca más popular para crear Mocks en proyectos Java y Android
  • MockK — una alternativa a Mockito para Kotlin con soporte nativo para corrutinas y clases selladas
  • Behavior verification — la diferencia clave entre Mock y Stub: Mock verifica el comportamiento, no el estado
  • Over-mocking — el principal antipatrón: los mocks solo deben usarse para dependencias externas

¿Qué es Mock?

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.

Cómo funciona Mock

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.

Cuándo es necesario Mock

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.

Mock vs. Stub: comparación detallada

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.

CriterioMockStub
Pregunta principal¿Se llamó al método?¿Qué resultado se devolvió?
VerificaciónComportamiento (verify)Estado (assert)
Devolución de datosOpcionalObligatoria
Ejemploverify(analytics).logEvent(“click”)assertEquals(5, repository.getCount())
Cuándo usarEfectos secundariosDevolución de datos

Regla práctica: Mock o no

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.

Mockito vs. MockK: comparación de bibliotecas

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: clásico probado

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: enfoque Kotlin-first

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.

kotlin
// Mockito + mockito-kotlin
val repository = mock<UserRepository>()
whenever(repository.getUser(1)).thenReturn(user)

// MockK
val repository = mockk<UserRepository>()
every { repository.getUser(1) } returns user

Comparación de rendimiento

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.

Ejemplos de pruebas Mock en Kotlin

Examinemos tres escenarios: probar un ViewModel con dependencias Mock, probar un UseCase verificando llamadas API y probar corrutinas con coVerify.

Ejemplo 1: ViewModel con Mock de analytics

kotlin
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") }
    }
}

Ejemplo 2: UseCase con verificación asíncrona

kotlin
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)
    }
}

Ejemplo 3: verificación de argumentos con ArgumentCaptor

kotlin
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])
    }
}

Mejores prácticas de pruebas Mock

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.

Mock solo en los límites externos de la aplicació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.

Un assert / verify por prueba

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).

  • Usa relaxUnitFun = true en MockK para métodos que devuelven Unit — de lo contrario Mock lanza una excepción en una llamada no especificada
  • Limita verify solo a llamadas críticas — no verifiques cada getter y setter, esto hace que las pruebas sean frágiles
  • Aplica ArgumentMatchers con criterio — any() oculta detalles importantes si el argumento es crítico para la lógica de negocio
  • No abuses de verifyNoMoreInteractions — este método vuelve las pruebas innecesariamente rígidas ante cualquier cambio en el código de producción
  • Usa @MockkAnnotations para la inicialización automática de objetos Mock — esto reduce el boilerplate y mejora la legibilidad

Técnicas avanzadas de pruebas Mock

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.

Mock parcial con spyK

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.

Probar StateFlow con Turbine

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.

kotlin
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

¿En qué se diferencia Mock de Mockito?

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).

¿Cómo funciona Mock con las corrutinas de Kotlin?

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).

¿Puede un Mock devolver diferentes valores en llamadas repetidas?

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.

¿Cómo limpiar el estado de Mock entre pruebas?

En MockK, usa la anotación @MockK con relaxed = true y llama a clearMocks(mock) en el método @After. En MockitoMockito.reset(mock). La mejor práctica: crear un nuevo Mock para cada prueba mediante @Before para eliminar la interferencia entre pruebas.

¿Cómo maneja Mock las clases selladas en Kotlin?

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

  • Mock — un tipo de Test Double que verifica el comportamiento (verify), no el estado (assert) de las dependencias
  • Mockito — el estándar para Java/Android, MockK — la elección Kotlin-first con soporte para corrutinas y clases selladas
  • Regla principal: Mock para límites externos (red, BD, servicios del sistema), objetos reales para clases internas
  • Over-mocking — el principal antipatrón: el reemplazo excesivo de dependencias hace que las pruebas sean frágiles y poco útiles
  • Una prueba — una verificación lógica: verify para Mock o assert para Stub, pero no ambos en la misma prueba
  • ArgumentCaptor / slot — la forma correcta de verificar argumentos de llamadas Mock en lugar de any() ciego
  • MockK se recomienda para proyectos Kotlin: coEvery y coVerify funcionan de forma nativa con corrutinas sin adaptadores adicionales

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.

Discutir el proyecto

Lea también