ConstructiCat Logo
CodeBust.
Browse section ▾

Prueba Desconocida.

Un método de prueba que ejercita el código pero no contiene ninguna aserción, por lo que pasa mientras no se lance ninguna excepción, dejando desconocidos su verdadero propósito y lo que verifica.

##Signs and Symptoms

Una prueba que prepara objetos y llama al sistema bajo prueba, y luego se detiene sin una sola aserción. Está en verde simplemente porque no se lanzó ninguna excepción, no porque se haya confirmado algún comportamiento esperado. Nada en el cuerpo indica qué aspecto tiene lo "correcto".

Señales reveladoras:

  • No hay expect/assert/verify en ninguna parte del cuerpo de la prueba.
  • "Verificación" realizada mediante console.log/print del resultado que se supone que un humano debe revisar a ojo.
  • Un nombre de prueba vago (testChainDependencies) y un cuerpo que no da ninguna pista de lo que garantiza.
  • La prueba seguiría en verde incluso si el método de producción devolviera un valor completamente incorrecto.
  • Pruebas que se apoyan por completo en "no lanzó excepción" sin decirlo explícitamente.
// Olor: ejecuta código, imprime, no afirma nada — pasa sin importar lo que devuelva calculate()
test('chain dependencies', () => {
  const game = Game.newGame(0, '');
  game.setOtherGoods(Building.TOOLMAKERS, 1);
  const logic = new Logic(game);

  const res = logic.calculateChainWithDependencies(Goods.TOOLS);
  console.log(res.toString()); // sin expect(...) — ¿qué está comprobando esto?
});

Una variante común se esconde tras un uso intensivo de mocks: la prueba configura los mocks y llama al SUT pero nunca afirma sobre un valor de retorno ni sobre las interacciones con los mocks.

##Reasons for the Problem

Por qué ocurre

  • Se generó el esqueleto de una prueba como marcador de posición/TODO ("haz que compile y se ejecute") y la aserción nunca se completó.
  • Un andamiaje de depuración —console.log, una ejecución manual de comprobación— se confirmó (commit) como si fuera una prueba.
  • Una refactorización eliminó o comentó la aserción pero dejó la preparación.
  • "Se ejecuta sin excepción" se confunde con "funciona". Las pruebas de humo son legítimas, pero aquí la intención de hacer una prueba de humo nunca se hace explícita.
  • Esbozos de prueba autogenerados o generados por IA que ejercitan un método sin comprobar el resultado.

Por qué es perjudicial

  • Falsa confianza. La prueba contribuye a la barra verde y a la cobertura de líneas/ramas, pero no verifica nada. Las métricas de cobertura mienten activamente sobre cuán protegido está el código.
  • Sin protección contra regresiones. El comportamiento puede romperse de forma silenciosa —valor de retorno incorrecto, estado incorrecto— y la suite permanece verde. Es el peor tipo de prueba: cuesta mantenimiento pero no detecta nada.
  • Intención desconocida. Un lector (o un futuro responsable de mantenimiento) no puede saber qué comportamiento está garantizado, por lo que no puede cambiar con seguridad el código ni la prueba. No documenta nada.
  • Erosiona la confianza en la suite. Una vez que la gente nota pruebas que en realidad no prueban nada, dejan de creer que verde significa correcto, socavando también todas las demás pruebas.

Es la imagen especular de la Ruleta de Aserciones: ese olor tiene demasiadas aserciones no documentadas; la Prueba Desconocida no tiene ninguna.

##Treatment

Haz que cada prueba indique lo que espera, y convierte "simplemente no debe lanzar excepción" en una elección explícita y deliberada.

  1. Añade al menos una aserción sobre un resultado observable —el valor de retorno, el estado resultante o un error lanzado. Reemplaza la depuración con console.log/print por un expect sobre ese valor.
  2. Si la verdadera intención es "esto no debe lanzar excepción", dilo explícitamente con expect(() => fn()).not.toThrow() (o await expect(fn()).resolves.toBeDefined()). Ahora la prueba de humo está documentada en lugar de ser accidental.
  3. Para pruebas que solo verifican interacciones, afirma sobre el colaborador: expect(mock).toHaveBeenCalledWith(...).
  4. Elimina o marca con skip/todo los marcadores de posición muertos en lugar de dejar una prueba verde vacía (it.todo('handles chained deps') registra el hueco honestamente sin falsear la cobertura).
  5. Activa un detector (jest/expect-expect, vitest/expect-expect o SonarSource S2699) en CI. Si envuelves las aserciones en ayudantes personalizados, regístralos mediante la opción assertFunctionNames de la regla para que las aserciones genuinas no se marquen.
// Antes — Prueba Desconocida
test('chain dependencies', () => {
  const logic = new Logic(Game.newGame(0, ''));
  const res = logic.calculateChainWithDependencies(Goods.TOOLS);
  console.log(res.toString());
});

// Después — la intención y la garantía son explícitas
test('resolves tools to the toolmakers workshop chain', () => {
  const logic = new Logic(Game.newGame(0, ''));
  const res = logic.calculateChainWithDependencies(Goods.TOOLS);
  expect(res).toHaveLength(1);
  expect(res[0].building).toBe(Building.TOOLMAKERS);
});

##Detected by

  • eslint-jest expect-expectjest/expect-expect
  • eslint-vitest expect-expectvitest/expect-expect
  • sonar S2699Las pruebas deben incluir aserciones (JavaScript)
  • sonar S2699Las pruebas deben incluir aserciones (Java)