32blogby Studio Mitsu

Generación de Tests con Claude Code: Guía Práctica de Testing Asistido por IA

Aprende a garantizar calidad en tests generados por IA con reglas CLAUDE.md, automatización con Hooks, flujos TDD con subagentes y testing de mutación con Stryker.

by omitsu14 min read
Contenido

Para obtener tests útiles de Claude Code necesitas tres capas: reglas en CLAUDE.md que definan estándares de calidad, Hooks que automaticen la ejecución de tests después de cada edición, y testing de mutación (Stryker) para verificar que los tests generados realmente detectan bugs — no solo inflan números de cobertura.

Pídele a Claude Code que "escriba tests" y obtendrás más de 20 tests en minutos. El problema es que la mitad podrían ser inútiles. Ejecuta Stryker contra tests generados por Claude y podrías ver puntajes de mutación en los 60 bajos. Casi el 40% de las mutaciones sobreviviendo significa que los tests se ven bien en papel pero no pueden detectar cambios reales en el código.

Los tests generados por IA son excelentes para inflar números de cobertura pero tienen dificultades para escribir tests que realmente detecten bugs. Tests duplicados cubriendo los mismos caminos de código, aserciones solo de camino feliz que ignoran casos borde, llamadas alucinadas a métodos que no existen — estos son los problemas típicos cuando dejas que Claude Code maneje la generación de tests sin supervisión.

Este artículo cubre el sistema que construí para solucionar esto: reglas en CLAUDE.md para imposición de calidad, Hooks para ejecución automática de tests, flujos TDD con subagentes, y testing de mutación para verificar cuantitativamente la calidad.

CLAUDE.mdDefinición de reglas de testRestringirHooksEjecución automática de testsAutomatizarImposición de TDDFlujo test-firstVerificarVerificación de calidadTesting de mutación

Por Qué Dejar que Claude Code Escriba Tus Tests

El testing es la parte más "tediosa pero necesaria" del desarrollo. Claude Code puede acelerar dramáticamente este trabajo.

Por qué Claude Code es fuerte en generación de tests:

  • Lee todo el codebase — entiende no solo las firmas de funciones, sino los sitios de llamada y dependencias, escribiendo tests con contexto completo
  • Ejecuta el ciclo test→fallo→corrección autónomamente — corrige tests fallidos e itera hasta que todo pase. Esto es fundamentalmente diferente de las completaciones inline de GitHub Copilot
  • Aprende de patrones de tests existentes — coincide con el estilo y convenciones de los tests que ya existen en tu proyecto

OpenObserve escaló de 380 a más de 700 tests usando el testing automatizado de Claude Code, reduciendo tests inestables en un 85%. El tiempo de análisis de características bajó de 45–60 minutos a 5–10 minutos.

Pero "escribir tests" como prompt no es suficiente. Necesitas sistemas que fuercen la calidad.


Los Problemas de los Tests Generados por IA

Cuando dejas que Claude Code genere tests sin barreras, estos problemas aparecen consistentemente.

1. Tests de peso muerto

Múltiples tests cubren el mismo camino de código. La cobertura sube pero la detección de bugs no mejora. Pídele a Claude que testee un generador de slugs para URLs y podrías encontrar tests que cubren el mismo camino de código con entradas trivialmente diferentes.

2. Sesgo de camino feliz

Claude genera tests para entradas normales e ignora caminos de error. Errores HTTP 500, arrays vacíos, entradas null y condiciones límite quedan ignorados. Los tests generados pasaban todos, pero la primera entrada malformada en producción habría sido catastrófica.

3. Alucinaciones

Tests que asumen que una función retorna una Promise cuando no lo hace, llaman métodos inexistentes o usan rutas de importación incorrectas. Algunos tests generados ni siquiera compilan.

4. Implementación primero por defecto

Sin instrucciones explícitas, Claude Code escribe código de implementación primero y tests después. Incluso cuando se pide TDD, vuelve a implementación primero a medida que el contexto se llena.

5. Confusión de framework

Usa APIs de Jest en un proyecto Vitest, crea archivos mock innecesarios o modifica archivos de configuración de tests sin permiso. Una vez encontré llamadas a jest.mock() en un proyecto que nunca había instalado Jest.

Intentar resolver esto con "prompts cuidadosos" tiene límites. Los sistemas que imponen reglas son la respuesta.


Definir Reglas de Test en CLAUDE.md

Escribir reglas de test en CLAUDE.md asegura calidad consistente desde el inicio de cada sesión. Si aún no has configurado CLAUDE.md, revisa primero la guía de patrones de diseño para CLAUDE.md.

markdown
# Testing Rules

## Framework
- Vitest 4.1 + React Testing Library + MSW for API mocking
- Test files: `__tests__/{module}.test.ts` (colocated with source)
- Config: vitest.config.ts (already configured, do not modify)

## Test Quality Rules
- NEVER write tests that only cover the happy path. Every test file must include edge cases
- ALWAYS test error paths: null input, empty arrays, network failures, validation errors
- NEVER mock what you don't own — use MSW for HTTP, real implementations for utilities
- ONE assertion focus per test. "should handle X" not "should handle X and Y and Z"
- ALWAYS include a descriptive test name that explains the expected behavior

## Test Structure
- Arrange-Act-Assert pattern for every test
- Use test.each() for parameterized tests instead of duplicating similar tests
- Group related tests with describe() blocks matching the function/component name

## Forbidden
- Do NOT modify vitest.config.ts or test setup files without asking
- Do NOT add snapshot tests (they pass trivially and catch nothing useful)
- Do NOT use jest.* APIs — this project uses Vitest (vi.*)
- Do NOT write tests after implementation. Write tests FIRST (TDD)

Aplicar reglas por patrón de archivo con .claude/rules/

Puedes cargar reglas adicionales solo cuando se trabaja con archivos de test usando reglas con alcance por ruta.

markdown
<!-- .claude/rules/testing.md -->
---
paths:
  - "**/*.test.ts"
  - "**/*.test.tsx"
  - "**/__tests__/**"
---

# Test File Rules
- Import from vitest: describe, it, expect, vi, beforeEach, afterEach
- Import from @testing-library/react: render, screen, fireEvent, waitFor
- Import from msw: http, HttpResponse for API mocks
- Always clean up: afterEach(() => cleanup())
- Prefer userEvent over fireEvent for user interactions

Esta regla se carga automáticamente en el contexto solo cuando Claude accede a archivos de test que coincidan. No consume tokens durante el trabajo de desarrollo normal.

Nota: las primeras versiones de Claude Code tenían problemas de parseo YAML con el frontmatter paths: (#17204, #13905). Estos problemas se han resuelto en gran parte — usa el formato de lista YAML mostrado arriba. Si también usas Cursor, ten en cuenta que Cursor usa globs: en lugar de paths: en sus archivos de reglas.


Automatizar Ejecución de Tests con Hooks

CLAUDE.md solo no puede prevenir violaciones de reglas. Los Hooks agregan imposición mecánica automatizando la ejecución de tests.

Ejecutar tests automáticamente después de ediciones

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx vitest run --reporter=verbose 2>&1 | tail -20"
          }
        ]
      }
    ]
  }
}

Cada edición de archivo ejecuta Vitest automáticamente. Claude ve los fallos inmediatamente y se auto-corrige.

Forzar que todos los tests pasen antes de que la sesión termine

json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "agent",
            "prompt": "Run the full test suite with `npx vitest run`. If any test fails, fix it before stopping. Do not stop until all tests pass.",
            "timeout": 120
          }
        ]
      }
    ]
  }
}

El hook Stop con tipo agent ejecuta un subagente antes de que Claude se detenga. Si los tests fallan, se corrigen automáticamente antes de que la sesión termine.

Efecto combinado

HookCuándoEfecto
PostToolUse + `WriteEdit`Cada edición de archivo
Stop + agentAntes de que termine la sesiónGarantiza que todos los tests pasen

Estos dos hooks juntos casi eliminan el escenario de "código sin tests siendo commiteado." Una vez que este combo está en su lugar, empezarás a detectar regresiones que de otro modo se te habrían escapado.


En Práctica: Agregando Tests a Código Existente

Un flujo de trabajo práctico para agregar tests a un proyecto Next.js existente.

Paso 1: Identificar objetivos de test

Encuentra funciones en este proyecto con baja cobertura de tests.
Prioriza lógica de negocio (lib/, utils/, actions/).

Claude Code escanea el codebase y lista módulos sin tests existentes.

Paso 2: Generar tests con prioridad

Escribe tests para lib/auth/validate-session.ts.
Incluye casos borde: token expirado, formato inválido, entrada null.

Solicita tests un módulo a la vez en lugar de todos los archivos a la vez. Esto mantiene el contexto enfocado y produce tests de mayor calidad.

Paso 3: Revisar tests generados

Puntos a verificar en los tests generados por Claude Code:

  • Cada test es independiente — sin estado compartido entre tests
  • Los casos borde están cubiertos — no solo caminos felices sino también caminos de error
  • Las aserciones son específicastoBe(true) o toEqual(expected) en lugar de toBeTruthy()
  • Los mocks son mínimos — nada mockeado más allá de lo necesario
Verifica si los tests generados tienen peso muerto (tests duplicados).
Elimina los que cubren los mismos caminos de código.

Flujo TDD: Forzando Test-First

Practicar TDD (Desarrollo Dirigido por Tests) con Claude Code requiere instrucciones explícitas y uso de subagentes.

Prompt básico de TDD

Usa TDD.

1. Escribe el test primero (RED) — el test debe fallar
2. Escribe la implementación mínima para pasar (GREEN)
3. Refactoriza (REFACTOR)

Ejecuta tests después de cada paso y muéstrame los resultados.

El problema de contaminación de contexto

Ejecutar Red→Green→Refactor en una sola sesión causa que el contexto de cada fase se filtre a la siguiente, degradando la calidad. Esto se llama contaminación de contexto — un factor clave en la gestión de tokens.

La solución es aislar cada fase en su propio subagente.

markdown
<!-- .claude/commands/tdd.md -->
Ejecutar flujo TDD.

1. Agente escritor de tests (RED):
   - Escribe tests desde los requisitos funcionales en $ARGUMENTS
   - Confirma que los tests fallen

2. Agente implementador (GREEN):
   - Lee solo los tests generados
   - Escribe código mínimo para pasar los tests

3. Agente refactorizador (REFACTOR):
   - Lee tanto tests como implementación
   - Refactoriza manteniendo los tests pasando

Cada agente se ejecuta con su propio contexto independiente, previniendo interferencia entre fases. Consulta el cheatsheet de comandos de Claude Code para más detalles sobre comandos slash personalizados.


Verificar la Calidad de Tests Generados por IA

Que un test exista y que un test detecte bugs son cosas diferentes. El testing de mutación te permite verificar cuantitativamente la calidad de los tests generados.

Qué es el testing de mutación

El testing de mutación introduce pequeños cambios (mutaciones) al código fuente y verifica si los tests los detectan.

  • if (a > b)if (a >= b)
  • Test falla → mutante "eliminado" (test es efectivo)
  • Test pasa → mutante "sobrevivió" (test es insuficiente)

Ejecutar tests de mutación con Stryker

Instala Stryker con el plugin de runner para Vitest:

bash
npm install --save-dev @stryker-mutator/core @stryker-mutator/vitest-runner
npx stryker run
typescript
// stryker.config.mjs
/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */
export default {
  testRunner: "vitest",
  mutate: ["src/lib/**/*.ts", "!src/lib/**/*.test.ts"],
  reporters: ["html", "clear-text"],
  vitest: {
    configFile: "vitest.config.ts",
  },
};

Leer los resultados

Mutation score: 78.5%
Killed: 51 | Survived: 14 | No coverage: 3
  • Superior a 85%: La calidad de tests es sólida
  • 70–85%: Faltan algunos casos borde
  • Inferior a 70%: Los tests necesitan revisión significativa

Corregir mutantes sobrevivientes con Claude

Lee el reporte de mutación de Stryker (stryker-report/mutation.html).
Agrega casos de test para los mutantes sobrevivientes.

Claude Code identifica dónde sobrevivieron los mutantes y agrega tests cubriendo esos caminos de código. Repite hasta que el puntaje de mutación supere 85%.


Preguntas Frecuentes

¿Claude Code soporta Vitest directamente?

Sí. Claude Code detecta tu framework de testing desde la configuración del proyecto. Si tienes vitest en tu package.json y un vitest.config.ts, usará las APIs de Vitest automáticamente. El problema es que a veces confunde las APIs de Jest y Vitest — por eso debes declarar el framework explícitamente en CLAUDE.md.

¿Puedo usar estos patrones con Jest en lugar de Vitest?

Por supuesto. Las reglas de CLAUDE.md, la configuración de Hooks y el flujo TDD son agnósticos al framework. Cambia npx vitest run por npx jest en los comandos del Hook, y actualiza la sección de framework en CLAUDE.md. Stryker también soporta Jest como test runner.

¿Cuántos tokens consume el Hook PostToolUse?

El Hook PostToolUse ejecuta Vitest y envía las últimas 20 líneas de salida a Claude. En un proyecto típico con 50-100 tests, esto agrega aproximadamente 200-400 tokens por edición de archivo. El Hook Stop con subagente agent es más pesado — presupuesta unos 2,000-5,000 tokens dependiendo de cuántas correcciones necesite hacer.

¿Vale la pena el costo extra de tokens del enfoque TDD con subagentes?

Para correcciones pequeñas o utilidades simples, no — escribe los tests normalmente. Para funcionalidades nuevas con lógica compleja (flujos de autenticación, transformaciones de datos, flujos multi-paso), el enfoque TDD con subagentes se paga solo produciendo código mejor estructurado y menos regresiones. Lo reservo para módulos donde diseñar bien la interfaz importa más que la velocidad.

¿Qué puntaje de mutación debo buscar?

85% es el punto óptimo práctico. Por debajo del 70% significa que tus tests tienen brechas reales. Por encima del 90% a menudo significa que estás escribiendo tests para caminos de código triviales. Enfoca el testing de mutación en lógica de negocio (lib/, utils/, actions/) — no pierdas tiempo mutando componentes UI o archivos de configuración.

¿Claude Code puede leer reportes HTML de Stryker directamente?

Claude Code puede leer la salida de texto de npx stryker run, que incluye detalles de mutantes sobrevivientes. Para el reporte HTML, necesitarás describir los hallazgos o pegar las secciones relevantes. El reporter clear-text en la configuración de Stryker le da a Claude suficiente detalle para apuntar a los mutantes sobrevivientes.

¿Cómo evito que Claude modifique mis archivos de configuración de tests?

Agrega reglas explícitas a CLAUDE.md: "No modificar vitest.config.ts ni archivos de setup de tests sin preguntar." Claude Code respeta estas instrucciones de forma confiable. Para mayor seguridad, agrega esas rutas de archivo a tu archivo .claudeignore.

¿Esto funciona con monorepos?

Sí, pero necesitarás reglas de test separadas en CLAUDE.md por paquete o usar reglas con alcance por ruta en .claude/rules/. La configuración de Hooks aplica a todo el proyecto, así que ajusta el comando de Vitest para apuntar al paquete específico: npx vitest run --project=packages/core.


Conclusión

La generación de tests de Claude Code no puede controlarse en calidad solo con ingeniería de prompts. Los sistemas que imponen reglas son la respuesta.

CapaRolConfiguración
CLAUDE.mdDefinir reglas de test (framework, estándares, patrones prohibidos)5 minutos
HooksAutomatizar ejecución de tests (PostToolUse + Stop)5 minutos
Flujo TDDForzar test-first (aislamiento con subagentes)10 minutos
Testing de mutaciónVerificar calidad de tests generados (Stryker)15 minutos

Define reglas en CLAUDE.md, fuerza la ejecución con Hooks, verifica la calidad con testing de mutación. Con estas tres capas en su lugar, Claude Code genera tests que detectan bugs — no tests que solo inflan números de cobertura. La configuración total toma unos 35 minutos — y desde entonces me ha ahorrado horas depurando tests malos.

Artículos relacionados: