Aserción Redundante.
Una aserción redundante compara un valor consigo mismo o con un literal que es igual por construcción, por lo que su resultado es fijo y nunca puede fallar realmente ni detectar una regresión.
##Signs and Symptoms
Una aserción es redundante cuando su resultado se decide antes incluso de que se ejecute el código bajo prueba: los operandos esperado y real son el mismo valor, o ambos son literales que se sabe que son iguales (o desiguales). El catálogo xUnit/Test Smells (Peruma et al.) la define como "un método de prueba que contiene una sentencia de aserción en la que los parámetros esperado y real son el mismo", y señala que la aserción es, por tanto, "o bien siempre verdadera o bien siempre falsa".
Cómo detectarlo:
- Un
assertEquals/toBe/toEqualcuyos dos argumentos son la misma expresión o variable. - Un literal booleano afirmado contra sí mismo, p. ej.
assertTrue(true)oexpect(true).toBe(true). - Una comparación que el compilador/linter puede demostrar que es constante, como
expect(x === x).toBe(true). - Una "comprobación de cordura" que reafirma una constante que acabas de declarar en lugar de ejercitar el sistema.
// Olor: el resultado es fijo, el código bajo prueba nunca interviene
test('user is active', () => {
expect(true).toBe(true); // siempre pasa
const status = 'active';
expect(status).toBe('active'); // reafirma el literal, no prueba nada
expect(user.id).toEqual(user.id); // valor comparado consigo mismo
});
Una señal fiable: puedes eliminar por completo el código de producción y la aserción sigue pasando en verde.
##Reasons for the Problem
Por qué ocurre
- Restos de depuración. El catálogo señala explícitamente que este olor "lo introducen los desarrolladores con fines de depuración y luego lo olvidan": un marcador de posición
assertTrue(true)codificado de forma fija que sobrevive hasta el commit. - Deriva por copiar‑pegar / refactorización. Se sustituye una variable en ambos lados de un
assertEquals, o se renombra un valor bajo prueba de modo que el esperado y el real colapsan en el mismo símbolo. - Tautología por construcción. Afirmar un valor contra el literal del que acaba de ser asignado, en lugar de contra una expectativa derivada de forma independiente.
- Teatro de cobertura. Se añade una aserción solo para satisfacer reglas del tipo "toda prueba debe afirmar algo", sin comprobar nada significativo.
Por qué es perjudicial
- Falsa confianza. La prueba está permanentemente en verde y cuenta para el tamaño de la suite y la cobertura, pero no verifica nada. No puede detectar una regresión, así que enmascara huecos en la red de seguridad.
- La fiabilidad carece de sentido. Una prueba que nunca puede fallar no aporta ninguna señal; una que siempre es falsa es peso muerto que se ignora o se
skipea. - Legibilidad. Los lectores malgastan esfuerzo reconstruyendo el comportamiento previsto a partir de una aserción que afirma una tautología; la prueba ya no documenta un requisito.
- Mantenibilidad. Las aserciones redundantes acumulan ruido, inflan las métricas y erosionan la confianza en la suite, animando a la gente a dejar de leer las aserciones con atención.
##Treatment
Reemplaza la tautología por una comprobación que vincule un valor esperado conocido de forma independiente con el resultado real producido por el sistema bajo prueba.
Pasos:
- Identifica la aserción de resultado fijo: el mismo operando en ambos lados, o dos literales iguales.
- Determina la verdadera intención. ¿Qué comportamiento se suponía que verificaba esta prueba? Si ninguno, la aserción (o toda la prueba) está muerta y debería eliminarse.
- Afirma sobre la salida del SUT, no sobre la entrada. Alimenta el sistema con una entrada real y compara su resultado calculado con un valor esperado codificado de forma fija y calculado a mano, no con una de sus propias entradas/variables.
- Mantén esperado/real diferenciados. Asegúrate de que el operando esperado sea una constante que escribiste a propósito y de que el operando real sea el valor de retorno del código bajo prueba (también corrige el olor relacionado de orden de argumentos incorrecto).
- Vuelve a ejecutar con la implementación rota (mútala) para confirmar que la aserción realmente puede fallar.
// Antes — redundante: el resultado es fijo
test('discount', () => {
const total = 100;
expect(total).toBe(100); // reafirma el literal
expect(applyDiscount).toBe(applyDiscount); // valor frente a sí mismo
});
// Después — significativo: entrada conocida -> salida esperada de forma independiente
test('applies a 10% discount', () => {
expect(applyDiscount(100, 0.1)).toBe(90); // resultado del SUT frente a expectativa calculada a mano
});
Si quedó un marcador de posición como assertTrue(true) de la depuración, elimínalo; si sustituía a una comprobación real, escribe esa comprobación.
##Detected by
- sonar javascript:S5863 — A las aserciones no se les debe pasar dos veces el mismo argumento
- sonar java:S5863 — A las aserciones no se les debe pasar dos veces el mismo argumento
- eslint no-constant-binary-expression — Prohibir expresiones donde la operación no afecta al valor (marca autocomparaciones / aserciones siempre verdaderas como assert(a === a))