Esto no debería ser una opinión polémica en pleno 2026, pero he visto a mucha gente presumir del número de tests de un proyecto como una medida de la calidad y de la confianza que podemos tener en el código.

Estas publicaciones y respuestas recrean ejemplos que veo casi a diario. He omitido la redacción original y los perfiles porque el objetivo no es criticar a personas concretas.

El número de tests es una métrica de vanidad

El número de tests es una métrica muy fácil de inflar. Cuando se le pide a un agente que “añada más tests”, el agente puede generar una gran cantidad de tests redundantes solo para cumplir la instrucción. Diferentes personas también puede dividir un escenario entre varios métodos o probar un detalle privado de la implementación desde distintos ángulos. La cifra aumentará sin proteger necesariamente más comportamiento ni hacer que el código sea más fiable ante los cambios.

La ley de Goodhart describe lo que ocurre cuando una medida se convierte en un objetivo que la gente intenta optimizar: deja de ser una medida fiable de aquello que pretendía representar. El coverage resulta útil para detectar código al que los tests no llegan, y el número de tests puede describir el tamaño de un proyecto, pero convertir estas cifras en objetivos puede transformarlas en algo que simplemente hay que aumentar. Si se fija un umbral de coverage, se añadirán tests que no comprueben necesariamente nada útil, mientras que si se fija un objetivo para el número de tests, los agentes generarán tests. Ninguna de las dos cifras demuestra confianza en el comportamiento que importa.

Qué nos puede decir el coverage

El coverage indica qué código se ejecutó durante los tests, pero no si sus asserts eran útiles ni si detectarían un error importante. Un test para una clase de acceso a datos puede mockear el cliente de base de datos, solicitar un registro a través de la clase y comprobar que devuelve el registro configurado en el mock. Puede ejecutar todas las líneas del método y mostrar un 100% de coverage, aunque en la práctica solo haya comprobado que el mock devuelve el valor que se le indicó.

Martin Fowler hace una distinción útil en su explicación sobre test coverage. El coverage tiene valor porque puede mostrar código al que los tests nunca llegan. Sin embargo, cuando la cifra ya es suficientemente alta, dice muy poco sobre la calidad de los tests o los fallos relevantes que pueden detectar. Una investigación llegó a una conclusión similar: después de controlar el número de tests, la relación entre coverage y detección de fallos era baja o moderada en el mejor de los casos.

Estas limitaciones ya existían antes de los agentes de programación, pero la IA hace que sean más fáciles de pasar por alto y mucho más fáciles de escalar.

La IA puede acoplar los tests a una implementación

Cuando un agente escribe los tests después de implementar una funcionalidad, suele verificar lo que el código ya hace. Un supuesto equivocado o un error existente puede convertirse en una expectativa de los tests, mientras que los detalles de implementación pasan a formar parte de aquello que protegen. Cambiar la implementación obliga entonces a cambiar también los tests, aunque el comportamiento visible desde fuera siga siendo el mismo. Esto añade fricción al desarrollo sin aumentar la confianza en la codebase.

El orden en esto es importante. Un test escrito antes de la implementación describe el comportamiento esperado sin verse condicionado por cómo se haya implementado la funcionalidad. Proporciona al agente un objetivo independiente y un ciclo de feedback claro: primero debe fallar el test y después debe cambiar la implementación hasta que pase.

Cuando los tests se generan después de implementar, la implementación puede convertirse en la principal fuente de verdad del agente. El agente deduce el comportamiento esperado a partir de los valores devueltos y los errores que ya existen en el código. Esto puede auemntar el coverage mientras conserva supuestos incorrectos y acopla detalles de implementación. Los tests pasan, pero quizá solo confirmen que el código se comporta exactamente como fue escrito, lo que no nos aporta nada de confianza.

Nada de esto implica que una colección grande de tests sea mala por sí misma. La pregunta importante es por qué existen esos tests y qué riesgos cubren.

Cuándo tiene sentido una colección grande de tests

SQLite es un buen ejemplo de un proyecto serio en el que una colección enorme de tests está completamente justificada. Su documentación pública describe 51.445 tests diferentes escritos en TCL. Su harness independiente TH3 añade más de 50.000 casos y ejecuta alrededor de 2,4 millones de instancias para obtener coverage completo.

Esa escala tiene una razón. SQLite se ejecuta en miles de millones de dispositivos, almacena datos persistentes, funciona en una gran variedad de plataformas y mantiene décadas de compatibilidad. Sus tests cubren fallos que serían irrelevantes para un servicio CRUD típico, como quedarse sin memoria, errores de entrada y salida en disco, cortes de corriente durante el commit de una transacción, bases de datos corruptas, diferentes codificaciones, tamaños de página, modos de journal y concurrencia. También compara su comportamiento con otros motores de bases de datos y utiliza fuzzing. La documentación de testing de SQLite explica especialmente bien para qué sirve una colección tan grande de tests.

La suite de SQLite tiene valor porque su tamaño responde al número y la gravedad de los riesgos que debe manejar el proyecto. Cada categoría de tests protege un comportamiento o modo de fallo concreto. Esa es la lección útil de su escala: los tests deben elegirse como respuesta a riesgos reales, no añadirse para mejorar una métrica.

Qué testear

La mayoría de los proyectos afrontan un conjunto de riesgos más reducido que SQLite, pero se aplica el mismo principio. Los tests deben partir de las consecuencias de un fallo en lugar de un número objetivo. El primer paso consiste en identificar los comportamientos que causarían un daño real si fallaran y después elegir el mecanismo más sencillo que pueda protegerlos.

Los fallos en producción proporcionan los ejemplos más claros. Cuando un bug llega a producción, hay que escribir un test que reproduzca el fallo y comprobar que falla antes de arreglar el código. Una vez que el cambio consigue que ese test pase, ese test debe conservarse para que el mismo bug no vuelva a aparecer. Siempre que sea posible, un incidente de producción debería dejar una marca en los tests.

No todas las garantías tienen que proceder de un test. Algunos estados inválidos pueden detectarse de forma más efectiva mediante el sistema de tipado. Probar qué ocurre cuando se pasa un número a una función que solo acepta strings aporta poco valor si un lenguaje tipado ya rechaza esa llamada. Sin embargo, los tipos no pueden proteger los los datos procedentes de usuarios, archivos, bases de datos y servicios externos. Estos necesitan validación porque no se vuelven fiables al entrar en una aplicación tipada.

Los comportamientos que sí requieren tests deben probarse en el nivel más sencillo que todavía proporcione una confianza significativa. La lógica de negocio pura normalmente puede probarse sin infraestructura, y suele ser mejor probar una clase de acceso a datos contra una base de datos temporal real porque su comportamiento importante incluye queries, constraints y transacciones. Un cliente mockeado no puede ofrecer la misma confianza.

Los mocks son especialmente útiles cuando la dependencia real es cara, inestable, lenta o está fuera de nuestro control, como una API externa. Su valor disminuye a medida que sustituyen una parte mayor del comportamiento que debería verificar el test. Un test aporta poca confianza cuando solo demuestra que un objeto mockeado devuelve el valor que hemos configurado unas líneas antes.

Seguir estos principios puede producir una suite pequeña o una grande. Lo que importa son los riesgos que cubre, los fallos que puede detectar y la libertad que proporciona para cambiar la implementación. El número de tests es una consecuencia de esas decisiones, no una prueba de su calidad.

Lecturas adicionales