Fake — qué es, propósito y cómo usarlo en pruebas

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

Fake es una implementación simplificada y funcional de una dependencia que se comporta como un componente real, pero utiliza almacenamiento en memoria u otros mecanismos ligeros en lugar de la infraestructura de producción. A diferencia de un stub, un fake contiene lógica de negocio real — ordenamiento, filtrado, agregación — simplemente sin efectos externos. Una base de datos en memoria en lugar de Room o un HashMap en lugar de SharedPreferences son ejemplos clásicos. Más detalles en la clasificación de test doubles de Martin Fowler.

Puntos clave

  • Fake — una implementación simplificada y funcional con lógica real pero sin dependencias externas
  • Almacenamiento en memoria — un repositorio fake almacena datos en un HashMap en lugar de una BD
  • Diferencia con Stub — un stub devuelve datos fijos, un fake contiene lógica ejecutable
  • Android — InMemoryUserRepository como Fake para probar ViewModel y UseCase
  • iOS — FakeNetworkSession con URLProtocol y datos de prueba en lugar de un servidor real

¿Qué es un Fake y por qué se necesita en las pruebas?

Fake es una implementación completa pero ligera de una interfaz, adecuada para pruebas. El término fue introducido por Gerard Meszaros (2007) en el libro “xUnit Test Patterns.” A diferencia de un stub, que devuelve respuestas fijas, un fake contiene código ejecutable: puede ordenar una lista, filtrar por condición, contar registros. La única diferencia con la implementación de producción es que un fake trabaja con datos en memoria y no realiza operaciones de E/S reales.

La principal ventaja es la velocidad. Las pruebas con un fake se ejecutan en milisegundos porque no hay acceso a disco, red o base de datos. Un HashMap en memoria funciona 100–1000 veces más rápido que Room o CoreData. Al mismo tiempo, un fake prueba la lógica de negocio real: ordenamiento, filtrado, agregación — todo lo que un stub no puede probar porque solo devuelve lo que se le indicó. Un fake brinda la confianza de que el código procesa datos correctamente, en lugar de solo recibir una respuesta predeterminada.

Cuándo es preferible Fake a Stub

Fake es preferible a Stub — si el componente bajo prueba realiza múltiples operaciones con datos (obtener, filtrar, ordenar, guardar), un stub requeriría configurar cada llamada individualmente. Un fake contiene la lógica internamente — la prueba simplemente llama a métodos y verifica el resultado. En IT Sectr, usamos fakes para todos los repositorios en pruebas unitarias: un repositorio fake con un HashMap cubre el 90% de los escenarios sin configurar Mockito o MockK.

Fake vs Stub vs Mock: cuándo elegir cada uno

Criterio de selección — determina qué verifica la prueba: estado o interacción. Si la prueba verifica el estado (el resultado del trabajo) y usa lógica — usa un fake. Si la prueba solo necesita datos de entrada sin lógica — un stub es suficiente. Si la prueba verifica que se llamó a un método — usa un mock. Mezclar tipos de test doubles en una misma prueba complica la comprensión y aumenta la fragilidad.

CriterioFakeStubMock
Tiene lógicaSí (simplificada)NoNo
VelocidadAltaMáximaAlta
Verificación de comportamientoIndirectaNoSí (verify)
MantenimientoUna clase por interfazConfigurar por pruebaConfigurar por prueba
RealismoAlto (el código funciona)Bajo (datos fijos)Medio
Riesgo de falsos positivosBajoMedioAlto (pruebas frágiles)

Antipatrón: Fake que no es fake — un error común cuando un desarrollador llama fake a un objeto que en realidad es un stub o un mock. Si tu InMemoryUserRepository no contiene lógica (filtrado, ordenamiento) — no es un fake, sino un stub con almacenamiento en memoria. Un fake se diferencia de un stub precisamente por la presencia de lógica ejecutable. Si un repositorio fake simplemente devuelve lo que se le puso y no procesa datos — usa un mock o un stub.

Regla práctica para elegir un Test Double

Recomendación práctica — comienza con un fake para cada repositorio o servicio. Si un fake supera las 50 líneas — divídelo en varias clases. Si no se necesita un fake en absoluto (la prueba solo verifica un único escenario con datos fijos) — usa un stub. Si la prueba verifica que se llamó a un método con parámetros específicos — usa un mock. No optimices la elección de antemano: escribe un fake, y si resulta excesivo, sustitúyelo por un stub en una prueba concreta.

Creación de objetos Fake en Android para Room y Retrofit

Repositorio fake para Room — un ejemplo típico de fake en Android. La implementación de producción de UserRepository usa Room DAO con consultas SQLite. La versión fake almacena datos en un MutableList o HashMap e implementa los mismos métodos: getUser(id), saveUser(user), deleteUser(id). El fake contiene lógica de búsqueda, filtrado y ordenamiento — igual que el repositorio de producción, pero sin SQL. Esto permite probar ViewModel y UseCase sin configurar una base de datos Room.

kotlin
class FakeUserRepository : UserRepository {

    private val users = mutableListOf<User>()

    override suspend fun getUser(id: String): User? {
        return users.find { it.id == id }
    }

    override suspend fun saveUser(user: User) {
        val index = users.indexOfFirst { it.id == user.id }
        if (index >= 0) users[index] = user
        else users.add(user)
    }

    override suspend fun search(query: String): List<User> {
        return users.filter {
            it.name.contains(query, ignoreCase = true)
        }
    }
}

Fake para API de Retrofit — en lugar de MockWebServer (que es un stub, no un fake), puedes crear una implementación de ApiService que devuelva datos desde una colección en memoria. La diferencia: MockWebServer intercepta HTTP y devuelve JSON, mientras que un fake ApiService funciona a nivel de interfaz de Kotlin sin serialización. Un fake es más rápido (sin análisis JSON) y más fácil de depurar (se ejecuta en el mismo proceso, tipado). Adecuado para pruebas donde la semántica HTTP (códigos de estado, cabeceras) no es importante.

FakeSharedPreferences para pruebas rápidas

— otro escenario común. SharedPreferences de producción escribe en disco mediante commit/apply. La versión fake almacena pares clave-valor en un HashMap y devuelve datos al instante. Soporta los mismos métodos: getString, putString, getInt, putInt, clear. Para Jetpack DataStore, el análogo es FakeDataStore con almacenamiento en memoria. Estos fakes aceleran las pruebas decenas de veces porque no hay operaciones de escritura en disco.

Implementaciones Fake en iOS con almacenamiento en memoria

Fake en Swift — se construye mediante protocolos. La clase de producción implementa el protocolo con lógica real (CoreData, URLSession). La estructura fake implementa el mismo protocolo con almacenamiento en memoria y lógica simplificada. Swift es un lenguaje con semántica de valor, por lo que las estructuras fake son inmutables y seguras en pruebas multihilo. Esto da una ventaja sobre los análogos de Android: no es necesario sincronizar el acceso a los datos en memoria.

swift
protocol UserRepositoryProtocol {
    func getUser(id: String) async -> User?
    func saveUser(user: User) async
}

final class FakeUserRepository: UserRepositoryProtocol {
    private var storage: [String: User] = [:]

    func getUser(id: String) async -> User? {
        return storage[id]
    }

    func saveUser(user: User) async {
        storage[user.id] = user
    }
}

final class UserViewModelTests: XCTestCase {
    func test_save_and_load() async {
        let fake = FakeUserRepository()
        let vm = UserViewModel(repository: fake)
        let user = User(id: "1", name: "Alice")

        await vm.saveUser(user)
        let loaded = await vm.getUser(id: "1")

        XCTAssertEqual(loaded?.name, "Alice")
    }
}

Fake para CoreData — en proyectos iOS, puedes crear un NSPersistentContainer en memoria configurando description.type = NSInMemoryStoreType. Esto es un stack completo de CoreData, pero funcionando en memoria. Este fake permite probar NSFetchRequest, predicados y ordenamientos sin crear un archivo SQLite. Velocidad: las pruebas en CoreData en memoria se ejecutan 5–10 veces más rápido que en el análogo en disco. La desventaja: hay que configurar NSManagedObjectModel cada vez.

FakeURLProtocol — una subclase de URLProtocol para interceptar solicitudes de red en iOS. Se registra mediante URLProtocol.registerClass(fakeProtocol). Internamente contiene un diccionario URL -> Data en memoria y devuelve datos sin una solicitud real. La diferencia con un stub: FakeURLProtocol puede verificar el cuerpo de la solicitud, las cabeceras y devolver diferentes respuestas según los datos de entrada. Esto es un fake porque contiene lógica de enrutamiento de solicitudes.

Patrones de uso de Fake en proyectos móviles

Fake como Test Fixture — coloca las clases fake en un módulo de prueba compartido (androidTest/sharedTest o TestSupport). Todas las pruebas del proyecto usan el mismo InMemoryUserRepository. Esto elimina la duplicación de configuración de objetos mock en cada prueba y garantiza un comportamiento uniforme. Cambiar la lógica del fake actualiza todas las pruebas simultáneamente. En IT Sectr, almacenamos las clases fake en sharedTest/java/com/itSectr/fake/ y las incluimos mediante implementation project(:sharedTest).

Fake con datos predefinidos — a menudo las pruebas necesitan un repositorio que ya contenga algunos registros. Solución: un método de fábrica fakeWithData(vararg items) o un método incorporado addDefaultData(). La fábrica crea un fake, lo llena con datos típicos y devuelve un objeto listo para usar. Esto reduce el boilerplate en las pruebas: en lugar de configurar llamadas mock, la prueba simplemente llama a FakeUserRepository.withUsers(alice, bob).

Fake con conteo de llamadas — a veces es necesario verificar no solo el estado, sino también la cantidad de invocaciones. Un fake puede contener contadores: saveCallCount, getUserCallCount. La prueba verifica el contador después de la ejecución. Esto es un compromiso entre un fake puro (verificación de estado) y un mock (verificación de interacción). Los contadores no verifican argumentos ni orden de llamadas — solo la cantidad. Para verificar argumentos, usa un mock.

Fake con Callback — para probar escenarios asíncronos, un fake puede aceptar un callback en cada llamada: beforeGetUser, afterSaveUser. Esto permite simular retardos, errores o verificar estados intermedios. Este enfoque es útil para probar estados de carga de la UI: el fake hace una pausa de 100 ms y la prueba verifica que la pantalla muestra un loader. El callback está ausente en producción — esto es funcionalidad puramente de prueba.

Preguntas frecuentes

¿En qué se diferencia Fake de Stub?

Fake contiene lógica funcional — filtra, ordena, cuenta. Stub solo devuelve respuestas predeterminadas sin lógica. Si un objeto tiene bifurcaciones (if/else, when) — es un fake. Si solo contiene valores de retorno — es un stub. Un fake es más costoso de mantener pero proporciona pruebas más realistas.

¿Cuándo puede ser perjudicial un fake?

Cuando la lógica del fake no coincide con la lógica de producción. Por ejemplo, FakeUserRepository usa búsqueda sensible a mayúsculas, mientras que la versión de producción no distingue mayúsculas. La prueba pasa, pero en realidad hay un error. Solución: prueba la lógica del fake por separado o usa fakes solo para interfaces con lógica simple (operaciones CRUD). Para lógica compleja, escribe pruebas de integración con una base de datos real.

¿Es un fake lo mismo que una base de datos en memoria?

Base de datos en memoria es un tipo de fake. Room.inMemoryDatabaseBuilder() crea SQLite en memoria que se comporta como una base de datos de producción. Esto es un fake completo. Pero un fake también puede estar a nivel de repositorio (sin SQL) y a nivel de red (FakeApiService). Una base de datos en memoria es un caso especial de fake donde la lógica está lo más cerca posible de la real.

¿Se pueden combinar Fake y Mock en una misma prueba?

Sí, pero con precaución. Fake para el repositorio (datos), Mock para AnalyticsTracker (verificación de eventos). Separación por capas: fake para la capa de datos, mock para la capa de analítica/registro. No hagas que un mismo objeto sea fake y mock a la vez — esto viola el Principio de Responsabilidad Única y confunde la prueba.

¿Cómo se prueba el propio Fake?

Prueba el fake con las mismas pruebas que la implementación de producción. Si tienes un UserRepositoryTest que verifica save, get, delete — ejecútalo dos veces: con FakeUserRepository y con RealUserRepository. Esto garantiza que el fake replica el comportamiento de la clase de producción. Si el fake comienza a comportarse de manera diferente — la prueba fallará en ambas implementaciones.

Resumen

  • Fake — una implementación simplificada y funcional de una dependencia con lógica de negocio real y almacenamiento en memoria
  • Diferencia con Stub — un fake contiene lógica (filtrado, ordenamiento), un stub solo devuelve datos
  • Velocidad — un fake funciona 100–1000 veces más rápido que la implementación de producción sin operaciones de E/S
  • Android — InMemoryUserRepository, FakeDataStore, Room en memoria mediante Room.inMemoryDatabaseBuilder
  • iOS — fake basado en protocolos, CoreData en memoria, FakeURLProtocol para interceptación HTTP
  • Mejor práctica — coloca los fakes en un módulo de prueba compartido y úsalos en todas las pruebas del proyecto
  • Prueba el fake — ejecuta las mismas pruebas en el fake y en la implementación de producción para verificar la consistencia

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