La cobertura de pruebas es una de esas métricas con las que todos están de acuerdo que importa y nadie quiere ser responsable de mejorar. Usted conoce el patrón: una base de código comienza con 90% de cobertura, luego algunas funcionalidades se lanzan sin pruebas, luego una refactorización omite la actualización de pruebas porque “volveremos a ello”. Seis meses después está en 60% y recuperarse se siente como un trabajo de tiempo completo para el que nadie se inscribió.
Este caso de estudio recorre cómo un equipo usó un flujo de trabajo de JieGou con el agente de código para pasar de 60% a 94% de cobertura de pruebas en tres semanas — automáticamente, con mínima intervención humana.
El problema
La base de código en cuestión era un backend de Node.js con 312 módulos. La cobertura había estado disminuyendo constantemente durante meses:
- 60% de cobertura general de pruebas, bajando de 85% al inicio del año
- 47 módulos con cero pruebas — principalmente funciones utilitarias, transformadores de datos y lógica de validación
- Nuevas funcionalidades lanzándose sin pruebas porque los desarrolladores estaban enfocados en plazos de entrega
- El pipeline de CI ejecutaba pruebas pero no aplicaba umbrales de cobertura, así que la disminución fue invisible hasta que alguien revisó
El equipo había intentado asignar “sprints de escritura de pruebas” dos veces. Ambas veces, el sprint fue desprioritizado cuando surgió una escalación de cliente. La escritura manual de pruebas es lenta, tediosa y compite con cada otra prioridad.
El flujo de trabajo
El equipo construyó un flujo de trabajo de 4 pasos en JieGou que se activa automáticamente cuando el código se fusiona a main. No se requiere intervención manual a menos que una prueba generada necesite revisión.
Paso 1: Disparador — webhook de GitHub al fusionar PR
El flujo de trabajo comienza con un disparador de webhook que se activa cuando un pull request se fusiona a main.
trigger:
type: webhook
source: github
events: ["pull_request.closed"]
filters:
- field: "action"
value: "closed"
- field: "pull_request.merged"
value: true
- field: "pull_request.base.ref"
value: "main"
La carga del webhook incluye la lista de archivos cambiados, el SHA del commit de fusión y los metadatos del PR. Todo esto alimenta el siguiente paso.
Paso 2: Analizar — identificar funciones sin probar
Un paso de receta toma la lista de archivos cambiados del webhook y la cruza con el reporte de cobertura más reciente. El prompt de la receta es directo:
step: analyze-coverage
type: recipe
model: claude-sonnet-4-6
input:
changed_files: "{{trigger.pull_request.changed_files}}"
coverage_report: "{{secrets.COVERAGE_REPORT_URL}}"
prompt: |
You are a test coverage analyst. Given the list of changed files
and the coverage report (lcov format), identify:
1. Which changed files have less than 80% line coverage
2. Which exported functions in those files have zero coverage
3. The function signatures and a brief description of what each does
Output a JSON array of objects with fields:
file_path, function_name, signature, description, current_coverage
Este paso produce una lista estructurada de exactamente qué funciones necesitan pruebas. Filtra archivos que ya tienen cobertura adecuada, así que el agente de código no pierde tiempo en código que ya está probado.
Paso 3: Generar — el agente de código escribe las pruebas
Aquí es donde el agente de código hace el trabajo pesado. Recibe la lista de funciones sin probar, clona el repositorio y escribe pruebas unitarias para cada una.
step: generate-tests
type: coding-agent
model: claude-sonnet-4-6
repo: "{{secrets.REPO_URL}}"
branch: "test-gen/{{trigger.pull_request.number}}"
maxTurns: 30
sandbox:
memory: "1GB"
timeout: "5m"
network: false
tools:
- read
- write
- edit
- bash
- glob
- grep
input:
untested_functions: "{{steps.analyze-coverage.output}}"
task: |
You are a senior test engineer. Your job is to write unit tests for
the following untested functions:
{{untested_functions}}
Instructions:
1. Read the source file for each function to understand its behavior
2. Read existing test files in the same directory for style conventions
3. Write tests using the project's test framework (vitest)
4. Each test file should cover: happy path, edge cases, error handling
5. Run `npm test -- --reporter=verbose <test-file>` after writing each
test file to verify all tests pass
6. If a test fails, read the error, fix the test, and re-run
7. Do NOT modify source code — only create or update test files
Match the existing test style: describe blocks, clear test names,
arrange-act-assert pattern. Use the existing fixtures and helpers
where available.
Las decisiones clave de configuración aquí:
- Modelo: Claude Sonnet 4.6 — lo suficientemente rápido para generación de pruebas de alto volumen, lo suficientemente inteligente para entender firmas de funciones complejas y casos extremos.
- Sandbox: 1 GB de memoria, tiempo límite de 5 minutos — suficiente espacio para ejecuciones de
npm testsin arriesgar procesos desbocados. - Red deshabilitada — el agente no necesita acceso externo; todo está en el repositorio clonado.
- maxTurns: 30 — permite al agente iterar sobre múltiples archivos de prueba y corregir fallos en varios ciclos.
La descripción de la tarea incluye una instrucción crítica: leer los archivos de prueba existentes primero. Esto asegura que las pruebas generadas coincidan con las convenciones del equipo — mismo estilo de aserciones, misma estructura describe/it, mismos patrones de fixtures. Sin esto, las pruebas generadas son técnicamente correctas pero estilísticamente inconsistentes, lo que crea fricción durante la revisión.
Paso 4: Enviar — crear un PR con resultados
Después de que el agente de código termina, un paso de receta final crea un pull request con las pruebas generadas e incluye los resultados de las pruebas en la descripción del PR.
step: submit-pr
type: recipe
model: claude-sonnet-4-6
input:
modified_files: "{{steps.generate-tests.modified_files}}"
test_output: "{{steps.generate-tests.output}}"
source_pr: "{{trigger.pull_request.number}}"
prompt: |
Create a pull request with the following:
- Title: "test: auto-generated tests for PR #{{source_pr}}"
- Body: Include a summary of tests added, functions covered,
and the full test output showing all tests passing
- Label: "auto-tests"
- Request review from the original PR author
El PR se etiqueta como auto-tests para que el equipo pueda filtrar y revisar en lote los PR de pruebas generadas. Solicitar revisión del autor original del PR significa que la persona más familiarizada con el código ve las pruebas primero.
Resultados
El equipo ejecutó este flujo de trabajo durante tres semanas en cada fusión a main. Estos son los números:
| Métrica | Valor |
|---|---|
| Cobertura inicial | 60% |
| Cobertura final | 94% |
| Pruebas generadas | 847 |
| Pull requests creados | 42 |
| Tiempo promedio de revisión de PR | 12 minutos |
| Pruebas que detectaron bugs existentes | 23 |
| Costo promedio por día | ~$4.50 (API de Claude) |
Algunos puntos destacados.
847 pruebas en 42 PRs significa aproximadamente 20 pruebas por PR. La mayoría de los PRs cubrieron 2-4 archivos fuente, con 5-6 pruebas por función (camino feliz, condiciones de frontera, casos de error, entradas null/undefined, casos extremos de coerción de tipos).
12 minutos de tiempo promedio de revisión es notable. La mayoría de las pruebas generadas estaban correctas en el primer intento. Los principales comentarios de revisión eran estilísticos — renombrar descripciones de pruebas, ajustar datos de fixtures para ser más realistas. Muy pocas pruebas necesitaron correcciones funcionales.
23 pruebas detectaron bugs reales en código existente. Este es el resultado más interesante. El agente de código escribió una prueba para una función de parseo de fechas que esperaba formato ISO 8601, y la prueba reveló que la función silenciosamente devolvía Invalid Date para marcas de tiempo con offsets de zona horaria. Ese bug había estado en producción durante cuatro meses. Descubrimientos similares en lógica de validación, errores de uno en uno en helpers de paginación, y una condición de carrera en un módulo de caché.
$4.50/día en costos de API de Claude es trivial comparado con el tiempo de ingeniería ahorrado. Una estimación conservadora: escribir 847 pruebas manualmente a 15 minutos por prueba tomaría aproximadamente 212 horas — más de cinco semanas del tiempo de un ingeniero a tiempo completo.
Lecciones aprendidas
Después de tres semanas ejecutando este flujo de trabajo, el equipo refinó su enfoque basándose en lo que funcionó y lo que no.
Comience con funciones puras
La primera versión del flujo de trabajo apuntó a todo el código sin probar. Esto funcionó bien para funciones puras — utilidades, validadores, transformadores, formateadores — porque tienen entradas claras, salidas claras y sin efectos secundarios. El agente podía leer la función, entender el contrato y escribir pruebas comprehensivas.
Los módulos complejos con conexiones a bases de datos, llamadas a API externas y estado mutable compartido eran más difíciles. El agente a veces generaba pruebas que simulaban demasiado o probaban detalles de implementación en lugar de comportamiento. El equipo ajustó el paso de análisis para priorizar funciones puras primero y poner en cola los módulos complejos para revisión manual.
Proporcione ejemplos de pruebas existentes
El cambio individual de mayor impacto fue agregar esta instrucción a la descripción de la tarea: “Lea los archivos de prueba existentes en el mismo directorio para convenciones de estilo.” Antes de esta instrucción, el agente producía pruebas que eran funcionalmente correctas pero usaban diferentes patrones de aserción, diferentes estructuras de bloques describe y diferentes convenciones de nombres que el resto de la suite de pruebas. Después de la instrucción, las pruebas generadas eran casi indistinguibles de las escritas a mano.
Ejecute pruebas antes de crear el PR
Las iteraciones tempranas del flujo de trabajo enviaban PRs con pruebas que no habían sido verificadas. Algunas tenían errores de importación, fixtures faltantes o fallos de aserción. Agregar el paso de npm test dentro de la tarea del agente de código — e instruirle a corregir fallos antes de terminar — eliminó casi todos estos problemas. El ciclo iterativo del agente (escribir prueba, ejecutar prueba, leer error, corregir prueba, re-ejecutar) es exactamente como trabajaría un humano, pero más rápido.
Revise por calidad, no solo cobertura
La cobertura es una métrica proxy. Una prueba que afirma expect(result).toBeDefined() técnicamente cubre la función pero no verifica comportamiento. El equipo agregó una checklist de revisión para PRs de pruebas generadas:
- ¿Cada prueba verifica un comportamiento significativo, no solo que la función se ejecuta?
- ¿Se cubren los casos extremos (entradas null, arrays vacíos, valores frontera)?
- ¿Las descripciones de prueba indican claramente qué comportamiento se está probando?
- ¿Las aserciones son específicas (
.toBe(42)no.toBeTruthy())?
La mayoría de las pruebas generadas pasaron esta checklist sin cambios. Las pocas que no lo hicieron fueron fáciles de detectar y corregir durante la revisión de 12 minutos.
La configuración completa
Para equipos que quieran replicar este flujo de trabajo, aquí está la configuración completa de pasos:
workflow:
name: "Auto Test Generation"
description: "Generate unit tests for untested code on PR merge"
trigger:
type: webhook
source: github
events: ["pull_request.closed"]
filters:
- field: "pull_request.merged"
value: true
- field: "pull_request.base.ref"
value: "main"
steps:
- id: analyze-coverage
type: recipe
model: claude-sonnet-4-6
# ... (ver Paso 2 arriba)
- id: generate-tests
type: coding-agent
model: claude-sonnet-4-6
dependsOn: [analyze-coverage]
# ... (ver Paso 3 arriba)
- id: submit-pr
type: recipe
model: claude-sonnet-4-6
dependsOn: [generate-tests]
# ... (ver Paso 4 arriba)
El flujo de trabajo se ejecuta de extremo a extremo en 8-15 minutos dependiendo del número de funciones sin probar. La mayor parte de ese tiempo es el agente de código iterando a través de archivos de prueba y ejecutando npm test después de cada uno.
Qué sigue
El equipo ahora está extendiendo el flujo de trabajo en dos direcciones:
- Pruebas de integración — un paso separado de agente de código que genera pruebas de integración para endpoints de API, usando los helpers de prueba y fixtures de base de datos existentes
- Aplicación de cobertura — una verificación de CI que falla la compilación si la cobertura cae por debajo del 90%, ahora que la línea base es lo suficientemente alta para aplicarla
La lección más amplia: la cobertura de pruebas no tiene que ser una tarea manual. Con el flujo de trabajo correcto, puede tratarla como un pipeline automatizado que se ejecuta junto con su CI/CD existente — sin sprints dedicados, sin desprioritización, sin deuda de cobertura.
El agente de código está disponible en planes Pro y superiores. Construya su primer flujo de trabajo de código.