---
title: "Assertion Roulette"
type: "test-smell"
slug: "assertion-roulette"
url: "http://localhost:3000/es/test-smells/assertion-roulette.md"
category: "Olores de aserción"
description: "Una prueba agrupa muchas aserciones sin documentar en un mismo método, de modo que cuando falla no puedes saber qué aserción se disparó ni por qué: te toca jugar a la ruleta."
---
# Assertion Roulette

> Una prueba agrupa muchas aserciones sin documentar en un mismo método, de modo que cuando falla no puedes saber qué aserción se disparó ni por qué: te toca jugar a la ruleta.

## Signs and Symptoms

Una sola prueba contiene una serie de aserciones desnudas, sin mensajes explicativos y sin un único objetivo claro. Cuando se pone en rojo, el informe de fallo (sobre todo una línea de resumen de CI o una función auxiliar de aserción compartida) te dice _que_ algo se rompió, pero no _qué_ comprobación ni _por qué_: juegas a la "ruleta" para encontrar al culpable.

Señales reveladoras:

* Muchas llamadas a `expect(...)` / `assert(...)` en una misma prueba, ninguna con un mensaje o etiqueta descriptivos.
* El nombre de la prueba es genérico (`'works'`, `'user profile'`, `'test register'`), de modo que un fallo no comunica nada por sí mismo.
* Las aserciones abarcan varias responsabilidades sin relación entre sí (un [Eager Test](https://en.wikipedia.org/wiki/Test%5Fsmell) que reutiliza un único fixture para comprobarlo todo a la vez).
* Un fallo te obliga a recurrir al depurador o a los números de línea para averiguar qué se estaba verificando en realidad.
* Como la mayoría de las aserciones fallan rápido, el primer fallo cortocircuita el resto, así que nunca ves las comprobaciones posteriores en una misma ejecución.

```js
test('user profile', () => {
  const user = createUser({ name: 'Ada', age: 36 });
  expect(user.name).toBe('Ada');
  expect(user.age).toBe(36);
  expect(user.isAdult).toBe(true);   // si ESTA es la que falla,
  expect(user.slug).toBe('ada');     // el informe solo dice
  expect(user.roles).toContain('member'); // "expected false to be true"
  expect(user.createdAt).toBeInstanceOf(Date);
});

```

Nota: los runners modernos (Jest, Vitest) imprimen la línea que falla y un diff, lo que atenúa el problema de "¿qué línea?". El olor sigue molestando cuando la prueba mezcla objetivos, tiene un nombre vago, itera sobre aserciones, las oculta tras funciones auxiliares compartidas o se ejecuta donde solo sobrevive un mensaje de resumen.

## Reasons for the Problem

**Por qué ocurre**

* _Eager Test / reutilización de fixtures._ Una preparación costosa tienta a acumular comprobaciones del tipo "ya que estoy aquí" en lugar de escribir una segunda prueba.
* _Verificación de objeto completo hecha a mano._ Comprobar un objeto campo por campo produce de forma natural una larga serie de aserciones sin documentar.
* _Crecimiento por copiar y pegar._ Las pruebas acumulan aserciones con el tiempo sin que nadie las divida.
* _Herramientas históricas._ Las aserciones clásicas de xUnit solo informaban éxito/fallo, así que una aserción sin etiqueta no daba ningún contexto al fallar: el origen del olor original de Meszaros.
* _Presión por los plazos._ Una sola prueba grande parece más rápida de escribir que varias enfocadas.

**Por qué es perjudicial**

* _Diagnosticabilidad / fiabilidad._ Según testsmells.org, "varias sentencias de aserción en un método de prueba sin un mensaje descriptivo perjudican la legibilidad/comprensibilidad/mantenibilidad, ya que no es posible entender el motivo del fallo". Pierdes tiempo localizando qué aserción se disparó.
* _Defectos ocultos (falsa confianza)._ Las aserciones de fallo rápido se detienen en el primer fallo, por lo que las aserciones posteriores nunca se ejecutan. Arreglas una, vuelves a ejecutar, encuentras la siguiente: se enmascaran varios errores y un "verde tras un único arreglo" transmite más seguridad de la que realmente da.
* _Legibilidad._ La prueba deja de documentar un único comportamiento; su intención queda enterrada en una lista, y un nombre de prueba genérico no aporta nada.
* _Mantenibilidad._ No queda claro si una nueva comprobación pertenece a esta prueba o a una nueva, así que el montón sigue creciendo y se acoplan responsabilidades sin relación entre sí.

## Treatment

Apunta al principio que hay detrás de una Single-Condition Test: **cada prueba verifica un comportamiento y puede fallar por exactamente un motivo.**

1. **Divide por objetivo.** Descompón la prueba ómnibus en pruebas enfocadas con nombres descriptivos. El nombre pasa entonces a _ser_ el mensaje de fallo.
2. **Condensa las comprobaciones campo por campo en una sola aserción.** Usa `toEqual` / `expect.objectContaining` / un snapshot revisado para que N aserciones se conviertan en un único diff con sentido.
3. **Cuando la agrupación es realmente cohesiva, etiqueta las aserciones.** El `expect` de Jest/Vitest no tiene argumento de mensaje, así que usa el parámetro de mensaje de `node:assert`, el `expect(actual, message)` de Vitest o `jest-expect-message`.
4. **¿Quieres que todas las comprobaciones se ejecuten e informen juntas?** Mejor divídelas; si no, usa aserciones suaves (`expect.soft` en Vitest) para que un fallo no oculte el resto.
5. **Protégete frente a regresiones** limitando las aserciones por prueba (consulta los detectores).

Antes: assertion roulette:

```js
test('register user', () => {
  const res = register({ email: 'a@b.com', age: 36 });
  expect(res.ok).toBe(true);
  expect(res.user.email).toBe('a@b.com');
  expect(res.user.isAdult).toBe(true);
  expect(res.welcomeEmailSent).toBe(true);
});

```

Después: un comportamiento por prueba, con una aserción de objeto completo:

```js
describe('register', () => {
  it('accepts a valid adult signup', () => {
    expect(register({ email: 'a@b.com', age: 36 }).ok).toBe(true);
  });

  it('stores the normalized user record', () => {
    const { user } = register({ email: 'a@b.com', age: 36 });
    expect(user).toEqual(
      expect.objectContaining({ email: 'a@b.com', isAdult: true }),
    );
  });

  it('sends a welcome email on signup', () => {
    expect(register({ email: 'a@b.com', age: 36 }).welcomeEmailSent).toBe(true);
  });
});

```

Si debes mantener una sola prueba, haz que cada aserción se describa a sí misma:

```js
import { strict as assert } from 'node:assert';
assert.equal(res.ok, true, 'registration should succeed');
assert.equal(res.welcomeEmailSent, true, 'welcome email should be sent');

```

## Detected by

- **eslint-jest** `jest/max-expects` — Marca el indicador basado en recuento de Assertion Roulette: informa cuando una prueba supera N llamadas a expect() (5 por defecto). La documentación señala que un mayor número de aserciones tiende a mezclar varios objetivos. (https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/max-expects.md)
- **eslint-vitest** `vitest/max-expects` — Equivalente en Vitest: impone un número máximo de aserciones expect() por prueba, detectando las pruebas que acumulan demasiadas comprobaciones. (https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/max-expects.md)
- **sonar** `java:S5961` — SonarSource 'Test methods should not contain too many assertions': limita las aserciones por prueba (25 por defecto para JUnit/AssertJ), el indicador estándar de análisis estático para este olor. (https://rules.sonarsource.com/java/RSPEC-5961/)
