Test Smells.
Recurring problems in test code — how to recognize each one, why it hurts, how to fix it, and the lint rules that detect it.
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.
Una Prueba ansiosa (Eager Test) verifica varios métodos o comportamientos distintos de la unidad bajo prueba en un solo método de prueba, en lugar de centrarse en un único comportamiento.
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.
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.
Un único método de prueba verifica la misma condición más de una vez —repitiendo una aserción idéntica o volviendo a comprobar lógica equivalente— en lugar de eliminar la comprobación redundante o dividir los casos distintos en sus propias pruebas enfocadas.
Una prueba verifica el comportamiento comparando la representación en cadena de un objeto (toString(), JSON.stringify(), HTML renderizado) con un literal de cadena esperado, acoplando la prueba al formato accidental en lugar de a los valores que realmente importan.
Una configuración compartida construye un gran fixture «todo en uno» que cubre las necesidades de todas las pruebas, pero cada prueba individual ejercita solo una pequeña parte de él.
Una prueba cuyas entradas o resultados esperados residen en un recurso externo —un archivo, una semilla de base de datos o una fixture compartida— de modo que no puedes entender ni confiar en la prueba leyéndola por sí sola.
El Optimismo de Recursos es cuando una prueba asume que un recurso externo (un archivo, directorio, tabla de base de datos, variable de entorno o endpoint de red) ya existe y está en un estado conocido, en lugar de aprovisionarlo y verificarlo, haciendo que la prueba pase o falle de forma no determinista.
Una clase de test inicializa los campos de su fixture en un constructor en lugar de en el hook de configuración dedicado del framework (setUp / @BeforeEach / TestInitialize), saltándose el ciclo de vida del test.
Una Prueba oscura es aquella en la que, solo a partir del método de prueba, un lector no puede saber qué escenario se prepara, qué comportamiento se ejercita ni qué resultado se espera, porque la intención queda sepultada bajo demasiado detalle, demasiado poco contexto o lógica oculta en otra parte.
Una prueba que usa `if`/`switch`/ternarios, bucles o `try`/`catch` para decidir qué ejecutar o aseverar, de modo que su comportamiento (y si verifica algo siquiera) depende de qué rama se ejecute en tiempo de ejecución.
La duplicación de código en los tests se da cuando el mismo código de configuración, acción o aserción se copia y pega en muchos tests, de modo que un solo cambio obliga a editar en muchos lugares y los tests se pudren convirtiéndose en copias frágiles casi idénticas.
Un test codifica de forma rígida literales numéricos sin explicar en sus entradas y aserciones, ocultando qué significan los números y de dónde salieron.
Una prueba que usa mucho más código del necesario para plantear su escenario, sepultando la única relación de causa y efecto que verifica bajo código repetitivo de preparación, datos irrelevantes y aserciones campo por campo.
Un test errático (inestable) pasa y falla de forma intermitente sobre el mismo código porque su resultado depende del tiempo, el orden, el estado compartido u otros factores no deterministas en lugar del comportamiento bajo prueba.
Una Sleepy Test pausa la ejecución con un retardo codificado de forma fija (`Thread.sleep`, `setTimeout`, `cy.wait(2000)`, `page.waitForTimeout`) para esperar a trabajo asíncrono, en lugar de esperar a la condición real.
Un Test Run War ocurre cuando las pruebas pasan para una persona pero fallan de forma aleatoria en el momento en que varias personas o trabajos de CI ejecutan la suite al mismo tiempo, porque las pruebas chocan sobre un fixture compartido y persistente.
Un test pasa o falla según qué otros tests se hayan ejecutado antes, porque los tests filtran y dependen de estado mutable compartido en lugar de que cada uno configure y desmonte su propio fixture.
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.
Una prueba hace aserciones sobre cómo funciona el código por dentro —campos privados, llamadas a métodos internos, estructura del DOM o clases CSS— en lugar del comportamiento observable del que depende un consumidor real.
Una prueba sobreespecificada afirma mucho más de lo que requiere el comportamiento bajo prueba (fija cadenas de salida exactas, formas de objeto completas, el orden de las colecciones o cada llamada a un colaborador interno), de modo que se rompe cada vez que cambia un detalle de implementación no relacionado.
Una Prueba Vacía es un método de prueba cuyo cuerpo no contiene sentencias ejecutables, por lo que siempre pasa sin verificar nada.
Una prueba que está confirmada en la base de código pero que nunca se ejecuta porque se ha omitido, desactivado o comentado, dando la apariencia de cobertura sin verificar nada en realidad.
El código de producción contiene lógica, ramas o miembros que existen únicamente para dar soporte a las pruebas, difuminando la línea entre lo que se entrega y lo que solo se prueba.
El código de producción contiene métodos, accesores de estado o costuras (seams) que existen únicamente para que los usen los tests, contaminando la API real e invitando a tests que verifican detalles internos en lugar de comportamiento.
Código de producción cuyo diseño (acoplamiento fuerte, dependencias ocultas, estado global, E-S no determinista o interfaces solo asíncronas) obliga a los tests a contorsiones incómodas, o hace imposible ejercitar una unidad en aislamiento.