Al escribir código de pruebas, hay un obstáculo inevitable.
Ese momento de confusión: «¿Esto es un Mock o un Stub?»
A veces parecen simples «objetos falsos», pero en una revisión de código escuchar «Eso no es un Mock, sino un Stub» nos deja en blanco.
En este artículo resumiré claramente, con ejemplos, las diferencias entre los cinco hermanos de los dobles de prueba (Dummy, Stub, Spy, Mock y Fake).
Empecemos por la conclusión.
Los dobles de prueba se distinguen por «qué se verifica». Si devuelve valores, es un Stub; si registra llamadas, un Spy; si evalúa si las llamadas eran las esperadas, un Mock; y si se comporta como el real, un Fake.
Con recordar esta frase, ya tienes la mitad hecha.
¿Qué es exactamente un doble de prueba?
Test Double (doble de prueba) viene del «doble de riesgo (stunt double)» del cine.
Como el doble que realiza escenas peligrosas en lugar del actor, es el término general para los objetos falsos que sustituyen a los reales.
Gerard Meszaros sistematizó este concepto en 『xUnit Test Patterns』 (2007).
Así que Mock y Stub son subtipos de dobles de prueba.
¿Por qué usarlos? Por ejemplo, al probar la lógica de pagos, no podemos llamar a la API real de la entidad emisora de tarjetas.
Es lento, cuesta dinero y las pruebas fallan si se interrumpe la red.
Por eso colocamos un sustituto que reemplace al sistema real.
Diferencias entre Mock, Stub, Spy y Fake: resumen en una tabla
Las explicaciones verbales confunden, así que veamos primero la tabla.
| Tipo | Función principal | Qué se verifica |
|---|---|---|
| Dummy | Solo ocupa el lugar | No se verifica |
| Stub | Devuelve un valor definido | Estado (resultado) |
| Spy | Registra el historial de llamadas | Estado + historial de llamadas |
| Mock | Determina si la llamada era esperada | Comportamiento (llamada) |
| Fake | Se comporta como el real, de forma ligera | Estado (resultado) |
Aquí solo hay una línea divisoria importante.
¿Verificamos el estado o el comportamiento?
Stub y Fake comprueban «si el resultado fue el esperado» (verificación de estado).
Mock comprueba «si realmente se llamó a ese método» (verificación de comportamiento).
Spy queda en medio y registra discretamente las llamadas.
Se entiende de inmediato al verlo en código
El código explica más rápido que las palabras. Tomemos como ejemplo una función de notificaciones de usuario. En Swift, es habitual crear directamente dobles de prueba que adopten un protocolo.
Empecemos por Stub: un sustituto que solo devuelve valores definidos.
// getNameFijar para que siempre devuelva «Hong Gil-dong»
final class UserRepositoryStub: UserRepository {
func getName(id: Int) -> String { "Hong Gil-dong" }
}
let service = GreetingService(repository: UserRepositoryStub())
// Comprobar solo que el resultado (estado) sea correcto
#expect(service.greet(id: 1) == "Hong Gil-dong")
El siguiente es Mock. Verifica «si se llamó a este método».
// Verificar si la notificación se envió (llamó) realmente
final class NotificationSenderMock: NotificationSender {
var sendCallCount = 0
func send(_ message: String) { sendCallCount += 1 }
}
let mockSender = NotificationSenderMock()
let service = UserService(sender: mockSender)
service.notifyUser(id: 1)
// Verificación de comportamiento: send¿Se llamó exactamente 1veces?
#expect(mockSender.sendCallCount == 1)
¿Ves la diferencia? Stub comprueba el valor devuelto (resultado) y Mock, el número de llamadas.
Esta diferencia de perspectiva es clave para entender los dobles de prueba.
Entonces, ¿cuándo se usan Spy y Fake?
Spy envuelve un objeto real: conserva su comportamiento, pero registra las llamadas en secreto.
Se usa cuando «quieres conservar la lógica real, pero también saber cuántas veces se llamó».
En Swift, es habitual crear directamente una clase Spy que delega en la implementación real y registra en propiedades los argumentos y el número de llamadas.
Fake se comporta de forma similar al real, pero es una implementación mucho más ligera.
Los ejemplos más comunes son un almacenamiento en memoria que sustituye a la base de datos real o un repositorio falso creado con Dictionary.
Se comporta como el real, pero no basta para producción: es una implementación exclusivamente de prueba.
En resumen, se dividen así.
- Solo necesito un valor → Stub
- Debo verificar si se llamó → Mock
- Necesito comportamiento real + registro de llamadas → Spy
- Necesito una implementación ligera que funcione como la real → Fake
Preguntas frecuentes
P. ¿En la práctica se pueden mezclar Mock y Stub?
En la práctica, una misma clase de doble de prueba hecha a mano suele devolver valores (Stub) y registrar llamadas (Mock), por lo que el límite es difuso. Aun así, hay que distinguir si el objetivo es proporcionar un valor o verificar una llamada para que la intención de la prueba quede clara.
P. He oído que no conviene usar demasiados Mock.
Si abusas de la verificación de comportamiento, las pruebas se rompen en cadena ante cualquier cambio interno. Por eso se recomienda priorizar la verificación de estado (Stub y Fake) y usar Mock solo para las relaciones de colaboración imprescindibles.
En vez de memorizar los cinco tipos, pregúntate: «¿Ahora necesito un valor o verificar una llamada?»
Con esa sola pregunta, sabrás naturalmente qué sustituto crear.
Si vuelves a confundirte al escribir pruebas, abre de nuevo este artículo. ¡Espero que tus pruebas sean mucho más sólidas!

