¿Qué hace crucible?
Cuándo usar esto
Cuando se solicite escribir, corregir o auditar pruebas unitarias en proyectos TypeScript.
Cuándo NO usar esto
Al escribir pruebas de extremo a extremo, integración, interfaz de usuario o simulación.
Exclusión voluntaria por proyecto
Antes de activar, verifica si el proyecto ha optado por no usar esta habilidad. Busca cualquiera de los siguientes:
- Un archivo
.no-crucibleen la raíz del proyecto "crucible": falseen cualquier parte deAGENTS.mdo.claude/settings.json
Si se encuentra alguna señal de exclusión, no actives la habilidad automáticamente; solo aplícala si el usuario lo solicita explícitamente en esta conversación.
Reglas
- Los comandos de ejemplo usan
pnpm, pero siempre usa el gestor de paquetes del proyecto. - No modifiques código de aplicación a menos que se te solicite explícitamente.
- Cuando se te pida agregar pruebas, no modifiques las pruebas existentes.
- Cuando se te pida corregir pruebas, no agregues nuevas pruebas.
- Cuando se te pida auditar pruebas, corrige las pruebas existentes y luego agrega pruebas según sea necesario para cumplir con los criterios de prueba.
Criterios de prueba
Las pruebas unitarias deben:
- Tener la máxima cobertura de ramas posible según Vitest.
- Matar todos los mutantes eliminables, logrando la máxima puntuación de mutación posible en todo el código dentro del alcance de la instrucción (no solo lo cubierto por las pruebas). Los mutantes no eliminables impedirán una puntuación del 100%.
- Ser basadas en propiedades siempre que sea posible, excepto si solo existen un puñado de casos de entrada. Por ejemplo, una función con un único parámetro booleano y sin entradas implícitas tiene solo dos casos de entrada posibles, así que no te molestes en hacerla basada en propiedades.
- (si es basada en propiedades) tener arbitrarios que cubran todos los parámetros posibles y entradas implícitas. Es vital que no se excluyan casos que podrían ocurrir en producción. Si es necesario o no está claro, prefiere hacer los arbitrarios demasiado amplios.
- Fallar si prueban código erróneo o si los arbitrarios se hacen intencionalmente demasiado amplios. Piensa en las pruebas como requisitos: deben nombrarse en consecuencia y deben pasar automáticamente tan pronto como el usuario corrija el error en el futuro después de que el usuario corrija la función y/o los arbitrarios. No uses
test.fails/.skip; esto hace que sea menos obvio para el usuario que se necesita atención, por lo que las pruebas que pasan cuando no deberían es el error de mayor prioridad a evitar.
Verifica la cobertura de ramas y ejecuta las pruebas: pnpm exec vitest run src/foo.test.ts --coverage
Verifica los mutantes supervivientes en el código que se está probando: pnpm exec stryker run --mutate "src/foo.ts"
Verificación de la configuración de pruebas
- Verifica que todos los siguientes paquetes estén instalados en el proyecto:
vitest fast-check @stryker-mutator/core @stryker-mutator/vitest-runner @stryker-mutator/typescript-checker - Verifica que las configuraciones de Vitest y Stryker incluyan/excluyan archivos correctamente. Stryker no debe verificar archivos que solo contengan datos de prueba.
- Verifica la configuración de Stryker:
- Usa el reportero
clear-text(otros reporteros son opcionales). - Usa el verificador de TypeScript y apunta correctamente al archivo de configuración de TypeScript.
- Usa el reportero
- Busca cualquier otro problema de configuración que pueda causar problemas en el flujo de trabajo de escritura de pruebas.
- Informa los hallazgos al usuario.
Escritura de pruebas
Cuando se te pida escribir nuevas pruebas, NO MODIFIQUES EL CÓDIGO DE LA APLICACIÓN NI LAS PRUEBAS EXISTENTES.
Primero, evalúa las pruebas existentes siguiendo Evaluación de un módulo. Crea un nuevo archivo de informe usando la plantilla y registra allí la cobertura inicial y las puntuaciones de mutación.
Segundo, escribe las pruebas siguiendo este proceso exactamente:
Haz lo siguiente para cada función/método en la interfaz del módulo, terminando una función antes de comenzar la siguiente:
- Determina el propósito de la función examinando comentarios, su nombre, su firma de tipo y cómo se usa. Si no estás seguro, anótalo en el informe, omite escribir pruebas y pasa a la siguiente función.
- Toma nota de cualquier posible error en la implementación de la función.
- Basándote en su propósito, identifica cualquier suposición incorrecta que la función haga sobre sus parámetros y entradas implícitas, y anota cualquier caso de entrada que probablemente lleve a un comportamiento incorrecto de la función. Por ejemplo, una función que toma un número entero positivo pero no valida su entrada hace una suposición incorrecta sobre su entrada.
- NUNCA MODIFIQUES LAS PRUEBAS PREEXISTENTES. Si encuentras algún problema en las pruebas existentes, notifica al usuario sobre los problemas encontrados.
- Escribe nuevas pruebas haciendo lo siguiente:
a. Usando
fast-check, crea stubs de pruebas basadas en propiedades con arbitrarios que cubran todos los parámetros posibles y entradas implícitas de la función. Usafc.asyncProperty+await fc.assert(...)cuando la función bajo prueba sea asíncrona. Si tienes dudas, prefiere hacer los arbitrarios demasiado amplios y menciónalo en el informe para que el usuario pueda corregirlos. Nombra las pruebas como descripciones del comportamiento deseado. b. Usandovitest, escribe aserciones dentro de los stubs que cubran cualquier valor devuelto y efectos secundarios como lanzar excepciones, mutar entradas, mutar/reasignar variables de ámbitos externos, etc. Asegúrate de que las pruebas afirmen el comportamiento deseado, detectando las suposiciones incorrectas/errores identificados anteriormente y fallando en consecuencia. - Vuelve a verificar la cobertura:
pnpm exec vitest run src/foo.test.ts --coverage - Prueba de mutación solo la función actual:
pnpm exec stryker run --mutate "src/foo.ts:<líneaInicio>-<líneaFin>" - Revisa las pruebas recién escritas y repite los pasos 5a y 5b hasta que se cumplan los criterios de prueba (listados arriba) para la función.
- Actualiza el informe con una sección sobre esta función.
Después de escribir las pruebas para todas las funciones, verifica dos veces que hayas agregado secciones al informe para cada función y termina escribiendo la sección de resumen.
Auditoría de pruebas
Si se te solicita auditar el proyecto en su totalidad, verifica la cobertura de código y las puntuaciones de mutación a nivel de proyecto, y recomienda áreas para auditorías más detalladas o para agregar/actualizar pruebas. Inclina las recomendaciones hacia las áreas más importantes y propensas a errores del código base: lógica de negocio central, código impulsado por eventos y funciones complejas.
Si se te solicita auditar una parte del proyecto, busca módulos o funciones (dentro del alcance de la instrucción) que no tengan pruebas e informa de estos al usuario en el informe posterior a la auditoría.
Para cada módulo dentro del alcance de la instrucción que tenga pruebas, sigue Evaluación de un módulo. Luego, si algún criterio de prueba aún no se cumple después de las correcciones de la evaluación, sigue Escritura de pruebas para llenar los vacíos restantes.
Evaluación de un módulo
Usa este proceso siempre que necesites evaluar un archivo de prueba existente contra los criterios de prueba, tanto antes de escribir nuevas pruebas como al auditar.
- Verifica la cobertura de código usando Vitest:
pnpm exec vitest run src/foo.test.ts --coverage. - Verifica los mutantes supervivientes usando Stryker Mutator:
pnpm exec stryker run --mutate "src/foo.ts". - Para cada función en el módulo que tenga pruebas:
- Para las pruebas basadas en propiedades:
- Busca entradas que la función aceptaría sin lanzar una excepción o devolver un valor de error, pero que no pueden ser generadas por los arbitrarios. Amplía los arbitrarios según sea necesario para incluir dichas entradas.
- Busca entradas que no estén cubiertas por los arbitrarios, especialmente entradas implícitas como campos de clase, variables globales, fecha/hora y números generados aleatoriamente. Agrega arbitrarios para estas.
- Corrige cualquier error en las implementaciones de mocks.
- Busca cuellos de botella de rendimiento.
- Para las pruebas basadas en propiedades:
- Registra la cobertura y las puntuaciones de mutación, junto con cualquier hallazgo, en el informe.
Informes de pruebas
Formatea los informes según la plantilla a continuación. Si no hay nada que informar en una subsección de función, simplemente escribe "n/a". Genera el informe en un archivo Markdown en debriefs/.
Informe: {nombreMódulo/nombreArchivo} {aaaa-mm-dd}
Resumen
Cobertura (ramas) Antes: X% → Después: Y% Líneas que no pudieron cubrirse: {rangos de líneas}
Puntuación de mutación (total) Antes: X% → Después: Y%
Problemas
{lista de viñetas de suposiciones incorrectas, errores encontrados, problemas en las pruebas y pruebas fallidas. Cada elemento de la lista debe comenzar con la ruta relativa a la raíz del proyecto y el número(s) de línea donde se encontró el problema}
{nombreFunción}
Propósito de la función {una oración que describa lo que se supone que hace la función} (confianza: alta | incierta) {si es incierta: qué no está claro y por qué}
Suposiciones incorrectas encontradas
- (línea {número/rango de línea}): {suposición sobre el tipo/rango/forma de entrada que la función no valida}
Errores encontrados en la implementación
- (línea {número/rango de línea}): {descripción + número de línea}
Problemas encontrados en pruebas preexistentes
- (línea {número/rango de línea}): {descripción del problema + nombre de la prueba}
Casos de prueba escritos
- {breve descripción de cada propiedad/invariante probado}
Pruebas fallidas
- (línea {número/rango de línea}): {nombre de la prueba + razón}
Mutantes no eliminables
- (línea {número/rango de línea}): {breve descripción}