---
title: "Excessive Mocking"
type: "test-smell"
slug: "excessive-mocking"
url: "http://localhost:3000/es/test-smells/excessive-mocking.md"
category: "Olores de mocking"
description: "Una prueba monta tantos objetos mock e interacciones simuladas que la configuración de mocks eclipsa la verificación real, de modo que la prueba acaba ejercitando los mocks en lugar del comportamiento real."
---
# Excessive Mocking

> Una prueba monta tantos objetos mock e interacciones simuladas que la configuración de mocks eclipsa la verificación real, de modo que la prueba acaba ejercitando los mocks en lugar del comportamiento real.

## Signs and Symptoms

Una prueba es mayormente _preparación_: largos bloques de creación de mocks, líneas `when(...).thenReturn(...)` / `mockReturnValue(...)` y `verify(...)`, con poco código real bajo prueba. Señales reveladoras:

* **Más fontanería de mocks que aserciones.** La preparación ocupa muchas líneas; el "actuar" es una sola llamada; el "aseverar" comprueba que los mocks fueron _llamados_ en lugar de que un resultado sea correcto.
* **Mockear cosas que son tuyas.** Se mockean objetos de dominio, objetos de valor o colaboradores de lógica pura en lugar de solo las fronteras externas (red, BD, reloj, sistema de ficheros, terceros).
* **Cadenas de mocks / "trenes descarrilados".** Un mock devuelve otro mock que devuelve otro mock, reflejando el grafo de llamadas de producción.
* **Verificación solo de interacciones.** La prueba asevera `toHaveBeenCalledWith(...)` sobre cada colaborador y nunca asevera el valor devuelto ni el estado resultante.
* **Frágil ante la refactorización.** Reordenar llamadas internas o extraer un método rompe muchas pruebas aunque el comportamiento no cambie.
* **Cinco o más mocks solo para instanciar el SUT**: suele ser señal de que el propio SUT tiene demasiadas dependencias.

```js
test('places order', () => {
  const inventory = { check: jest.fn().mockReturnValue(true) };
  const pricing   = { quote: jest.fn().mockReturnValue(42) };
  const tax       = { calc:  jest.fn().mockReturnValue(4.2) };
  const wallet    = { charge: jest.fn().mockReturnValue({ ok: true }) };
  const ledger    = { record: jest.fn() };
  const emailer   = { send: jest.fn() };
  const audit     = { log: jest.fn() };
  const clock     = { now: jest.fn().mockReturnValue(0) };

  const svc = new OrderService(inventory, pricing, tax, wallet, ledger, emailer, audit, clock);
  svc.place(cart);

  // asevera que se llamó a los mocks, no que el pedido sea correcto
  expect(inventory.check).toHaveBeenCalled();
  expect(pricing.quote).toHaveBeenCalled();
  expect(wallet.charge).toHaveBeenCalledWith(46.2);
  expect(ledger.record).toHaveBeenCalled();
});

```

## Reasons for the Problem

**Por qué ocurre**

* **El SUT tiene demasiados colaboradores.** El mocking excesivo suele ser una señal de _diseño_: una clase con poca cohesión y muchas dependencias obliga a cada prueba a levantarlas todas. Como dice la literatura del catálogo, _"si necesitas mockear cinco clases internas solo para probar un método, el método tiene demasiadas dependencias: es un problema de diseño, no de pruebas"._
* **Costumbre / reflejo de "mockearlo todo".** Llevar al extremo las pruebas basadas en interacciones ("escuela de Londres"), o mockear por reflejo para evitar tocar una BD o la red, lleva a mockear lógica pura que podría probarse directamente.
* **Objetos reales difíciles de construir.** Cuando los colaboradores reales son incómodos de instanciar, un mock parece más fácil que arreglar el constructor o añadir un fake.

**Por qué es perjudicial**

* **Falsa confianza.** Los mocks codifican _tus suposiciones_ sobre una dependencia. Si la implementación real diverge, la prueba sigue pasando; por ejemplo, un stub que afirma que `sum()` devuelve solo enteros positivos mantiene la prueba en verde después de que el método real cambie. Tales pruebas pueden volverse tautológicas: solo verifican que los mocks que escribiste se comportan como los mocks que escribiste. Como advierte la propia documentación de Mockito, _"si todo está mockeado, ¿estamos probando de verdad el código de producción?"_
* **Fragilidad / mantenimiento elevado.** Verificar llamadas concretas convierte los detalles de implementación en el contrato, así que refactorizaciones inofensivas (orden de llamadas, helpers extraídos) rompen las pruebas. Es el _Overspecified Software_ / _Fragile Test_ de Meszaros.
* **Mala legibilidad.** Cientos de líneas de configuración de dependencias entierran lo único que de verdad prueba el test, muy parecido a un _Mystery Guest_: un revisor no puede saber qué comportamiento se está aseverando realmente.
* **Errores de integración no detectados.** El cableado real entre componentes nunca se ejercita; los errores viven precisamente en las costuras que los mocks reemplazaron. Una cobertura alta enmascara una calidad baja.

## Treatment

Trata el mocking abundante como una señal de retroalimentación y luego reduce la _necesidad_ de mockear:

1. **Arregla primero el diseño.** Si debes mockear más de 5 colaboradores para construir el SUT, divide responsabilidades o reduce las dependencias del constructor. Menos dependencias reales significa menos mocks.
2. **Mockea solo en las fronteras de la arquitectura.** Mockea lo que _no es tuyo_ (red, BD, reloj, sistema de ficheros, APIs de terceros); usa **instancias reales** de tus propios objetos de dominio y de valor.
3. **Extrae un núcleo puro (núcleo funcional / cáscara imperativa).** Saca la lógica de cálculo/decisión de la clase intensiva en E/S para poder probarla con **cero mocks**, dejando una cáscara fina que solo necesita uno o dos dobles de frontera.
4. **Prefiere la verificación de estado a la verificación de interacciones.** Asevera el valor devuelto o el estado resultante en lugar de `verify(...)`/`toHaveBeenCalledWith(...)` sobre cada colaborador. Reserva las comprobaciones de interacción para el único efecto secundario que de verdad importa.
5. **Usa el doble más simple que funcione.** Sustituye los mocks elaborados por **stubs** (que solo devuelven valores) o un único **fake en memoria** reutilizable en vez de volver a stubear cada método en cada prueba.
6. **Haz aflorar el exceso de mocking de forma dinámica.** Activar el strict stubbing de Mockito (el `MockitoExtension`/`MockitoJUnitRunner` por defecto) lanza `UnnecessaryStubbingException` para los stubs que se configuran pero nunca se usan: una forma barata de encontrar mocks que no necesitabas.

```js
// ANTES: 8 mocks, aseverando llamadas
const pricing = { quote: jest.fn().mockReturnValue(42) };
const tax     = { calc:  jest.fn().mockReturnValue(4.2) };
// + 6 mocks más ...
expect(wallet.charge).toHaveBeenCalledWith(46.2);

// DESPUÉS: lógica pura probada directamente, sin mocks
expect(totalFor(cart, rates)).toBe(46.2);

// solo se finge la frontera real; asevera el estado, no las llamadas
const wallet = new InMemoryWallet({ balance: 100 });
const svc = new OrderService(new InMemoryInventory(cart), wallet);
const order = svc.place(cart);
expect(order.total).toBe(46.2);
expect(wallet.balance).toBe(53.8);

```
