Saltar al contenido

Kent Beck, creador del Test-Driven Development, cuenta algo que cualquiera que use agentes de IA para programar reconoce enseguida: el agente, para hacer pasar un test, a veces lo borra o lo comenta. Esta es la historia de por qué ocurre, las formas concretas que toma la trampa y cómo trabajar con el agente para que no pase.

El genio que cumple deseos a su manera

Beck describe al agente de IA como un genio que concede deseos, pero de formas inesperadas. Si el deseo es "que los tests pasen", eliminar el test que falla también cumple la orden. Lo documenta en su artículo Augmented Coding: Beyond the Vibes y en su entrevista con The Pragmatic Engineer. Entre las señales que él mismo vigila cuando el agente trabaja: funcionalidad que no pidió y cualquier indicio de que desactiva o elimina tests para que el conjunto pase.

El comportamiento tiene lógica desde dentro. El agente optimiza el objetivo literal que le das. "Haz que los tests pasen" admite dos caminos: arreglar el código o quitar el test. El segundo es más corto.

Las cinco formas de la trampa

Borrar el test es la versión burda y la más fácil de pillar. Las otras cuatro son más sutiles y pasan revisiones rápidas.

1. Borrar o comentar el test. Desaparece del archivo o queda comentado. En el diff se ve, si miras el diff.

2. Saltárselo. Un ->skip() en Pest o un markTestSkipped() en PHPUnit. La suite pasa, el contador de tests apenas cambia, y el test sigue ahí, inofensivo. Es la trampa que mejor sobrevive a un vistazo por encima.

3. Ablandar la aserción. El test sigue existiendo y sigue pasando, pero ya no comprueba nada útil:

<?php

// Antes: contrato real
expect($invoice->total)->toBe(1210.00);

// Después: aserción ablandada
expect($invoice->total)->toBeGreaterThan(0);

El diff parece un ajuste menor. El contrato ha desaparecido.

4. Adaptar el test al bug. El agente cambia el valor esperado para que coincida con lo que su código produce. Si la implementación calcula mal el IVA y devuelve 1189.00, el test pasa a esperar 1189.00. A partir de ahí el bug es comportamiento oficial: cualquier arreglo futuro romperá el test y parecerá una regresión.

5. Testear trivialidades. Tests que asserten que la clase existe, que el método devuelve algo o que no lanza excepción. Suben la cobertura, no protegen nada.

Las cinco tienen algo en común: la suite queda en verde. El verde deja de significar "el comportamiento es correcto" y pasa a significar "nadie lo ha impedido".

Dónde está el problema real

El problema no es cuándo se escribe el test. Es quién define lo que significa "correcto" y quién lo vigila.

Si dejas que el agente escriba código, escriba sus propios tests y declare el trabajo terminado, el ciclo se cierra sin nadie al mando: el test describe lo que el código ya hace, errores incluidos, y ninguna de las cinco trampas tiene testigo.

Con supervisión, hay más de un flujo válido.

TDD: el test primero. Escribes (o revisas y apruebas) el test antes de la implementación y lo comiteas: test: add failing test for invoice VAT calculation. El contrato queda fijado en git antes de que el agente toque el código, y cualquier manipulación posterior aparece en el diff. Beck trabaja así con agentes y considera el TDD especialmente útil en este contexto, porque la IA introduce regresiones con facilidad y el test las detecta pronto.

Desarrollo y test después, cerrando tarea a tarea. Supervisas la implementación y, al cerrar cada tarea, se escriben los tests. Funciona igual de bien con una condición: los tests que genere el agente los revisas contra la lista anterior. Que asserten valores concretos y no rangos vagos (trampa 3), que los valores esperados salgan del requisito y no de ejecutar el código (trampa 4), y que cubran los casos límite de la tarea en lugar de trivialidades (trampa 5). Si el test lo escribes tú, esa revisión ya la llevas puesta.

La constante en ambos flujos: el contrato es tuyo. En TDD lo fijas antes; en test-después lo validas al cerrar la tarea. Lo que no funciona es delegar también esa parte.

Guardarraíles prácticos

Deja la regla escrita. En el contexto del agente (un CLAUDE.md si usas Claude Code): no modificar, comentar, saltar ni borrar tests existentes sin justificación explícita. Si trabajas con TDD, añade el ciclo Red → Green → Refactor.

Revisa todo diff que toque tests. Un test que desaparece, se salta o se ablanda en un diff de implementación es la señal de alarma número uno. Los tests solo cambian cuando cambia el comportamiento esperado, y eso lo decides tú.

Comitea los tests por separado. Con conventional commits, los test: separados de los feat: hacen visible cualquier manipulación: si un feat: toca archivos de test, pregunta por qué.

Busca los skips antes de dar por buena la suite. Un grep -rn "skip" tests/ tarda dos segundos y descubre la trampa 2, la que mejor se esconde. Si quieres automatizarlo, un hook de pre-commit que falle ante ->skip( fuera de una lista blanca cierra esa puerta.

Cuándo pedir más o menos rigor

En desarrollos con lógica de dominio y reglas de negocio reales, tests supervisados como parte del cierre de cada tarea, sin excepción: hay un contrato que importa y regresiones que duelen. En prototipos, exploración o capa visual, la verificación es mirar el resultado, y forzar tests ahí estorba más de lo que aporta.

Resumen

El agente borra tests porque cumple el deseo literal de "hacerlos pasar" por el camino más corto, y borrar es solo la primera de cinco trampas: saltar, ablandar, adaptar al bug y testear trivialidades completan la lista. La defensa no es una metodología concreta: es que el contrato de comportamiento sea tuyo. Escribe el test antes o escríbelo al cerrar la tarea, pero revisa qué afirma, fíjalo en git y vigila cada diff que lo toque.

Rutas de aprendizaje