Ni cero tests ni cobertura total, el testing justo para tu proyecto

13/02/2026
funambulista cruzando entre dos edificios

Hay equipos que no testean nada y rezan en cada despliegue. Y hay equipos que buscan el 100% de cobertura y no entregan a tiempo. Los dos tienen un problema de testing. La pregunta no es si hay que testear, sino cuánto, dónde y por qué.

Tu equipo tiene un proyecto en producción. Cada vez que tocáis algo, alguien pregunta: "¿hemos probado esto?". La respuesta suele ser un silencio incómodo o un "creo que sí". Y cuando las cosas se rompen —que se rompen—, la conversación siempre es la misma: "necesitamos más tests".

Pero "más tests" no es una estrategia de testing. Es una reacción emocional a un bug en producción. Y suele llevar a uno de dos extremos: o el equipo sigue sin testear (porque nadie tiene tiempo), o alguien decide que hay que cubrir todo y el equipo pasa más tiempo escribiendo tests que código de producto.

La pregunta que deberías estar haciéndote no es "¿cuántos tests tenemos?". Es "¿estamos testeando lo que importa?". Y la respuesta a esa pregunta cambia según tu proyecto, tu equipo y la fase en la que estás.

El mito de la cobertura al 100%

Existe una idea persistente en la industria: que un buen proyecto tiene una cobertura de tests cercana al 100%. Es una métrica fácil de medir, fácil de poner en un dashboard y fácil de convertir en objetivo. Y es una de las peores métricas para decidir si tu testing es suficiente.

Un proyecto puede tener un 95% de cobertura y romperse en producción cada semana. ¿Cómo? Porque la cobertura mide que una línea de código se ejecuta durante un test, no que el test verifica algo útil. Un test que llama a una función pero no comprueba el resultado suma cobertura sin aportar confianza.

Martin Fowler lo explica bien: la cobertura te dice qué código no está testeado, pero no te dice si el código testeado está bien testeado. Es un indicador de huecos, no de calidad. Si tu equipo se obsesiona con el número, acabará escribiendo tests para cubrir líneas triviales (getters, setters, constructores) mientras ignora la lógica de negocio compleja que es donde viven los bugs de verdad.

La cobertura es útil como brújula. Si tienes un 15%, probablemente hay zonas críticas sin proteger. Si tienes un 85%, perseguir el 100% probablemente no vale el esfuerzo. Pero usarla como objetivo es como medir la salud de una empresa solo por el número de empleados.

La pirámide de testing (y por qué importa el orden)

Si hay un modelo que ha sobrevivido al paso del tiempo es la pirámide de testing. La idea es simple: muchos tests unitarios en la base, menos tests de integración en el medio, y pocos tests end-to-end en la cima.

Tests unitarios verifican piezas pequeñas de lógica de forma aislada. En un backend Django, un test unitario comprueba que una función calcula bien un precio con descuento o que un serializer valida correctamente los datos de entrada. Son rápidos de escribir, rápidos de ejecutar y baratos de mantener. Un proyecto Django bien testeado puede ejecutar cientos de tests unitarios con pytest en segundos.

Tests de integración verifican que varias piezas funcionan juntas. Que la vista de Django devuelve el JSON correcto cuando recibe una petición, que el ORM genera la query esperada, que la API responde con el código de estado adecuado. Son más lentos que los unitarios y requieren más infraestructura (base de datos de test, por ejemplo), pero detectan problemas que los unitarios no ven.

Tests end-to-end simulan el flujo completo del usuario. En una app Flutter, eso significa que el test abre la app, navega por pantallas, rellena un formulario y verifica que el resultado es correcto. Son los más lentos, los más frágiles y los más caros de mantener. Pero cuando pasan, dan una confianza que ningún otro tipo de test puede dar.

La pirámide funciona porque te dice dónde invertir. Si tu equipo tiene recursos limitados —y todo equipo los tiene—, invierte primero en la base. Muchos tests unitarios buenos son más valiosos que unos pocos tests end-to-end frágiles.

Cuánto testing necesitas según la fase de tu proyecto

Aquí es donde la mayoría de guías fallan: tratan el testing como algo estático. "Tu proyecto necesita X% de cobertura." Pero la cantidad de testing que tiene sentido depende de dónde estás.

Fase de validación (MVP, prototipo). Si estás validando una idea con un producto mínimo viable, testearlo todo es un error de prioridad. El producto puede pivotar la semana que viene, y esos tests que escribiste para un flujo que ya no existe son tiempo perdido. En esta fase, los tests imprescindibles son pocos: que la app arranca, que el flujo principal funciona y que los pagos (si los hay) no fallan. Todo lo demás puede esperar.

Fase de crecimiento. Tu producto tiene usuarios, está generando valor y el equipo añade funcionalidades. Aquí es donde el testing empieza a pagar dividendos reales. Cada nueva feature debería llevar tests de la lógica de negocio que introduce. Los bugs que aparecen en producción deberían generar un test de regresión antes de arreglarse (primero escribes el test que reproduce el bug, después lo corriges). El objetivo no es cubrir todo: es proteger lo que ya funciona mientras construyes lo nuevo.

Fase de madurez. Tu producto es estable, tiene una base de usuarios consolidada y los cambios tienden a ser incrementales. Aquí la inversión en testing se centra en los flujos críticos de negocio: el checkout, el registro, la integración con servicios externos. Un test end-to-end que verifica el flujo de compra completo vale más que cincuenta tests unitarios de funciones auxiliares.

Fase de escala. Múltiples equipos trabajan sobre la misma base de código. Los tests pasan de ser una herramienta de calidad a ser una herramienta de coordinación. Si el equipo A cambia una API interna y los tests del equipo B fallan, el pipeline de CI/CD lo detecta antes de que llegue a producción. En esta fase, la inversión en tests de integración y contratos es donde está el mayor retorno.

La regla del 80/20 aplicada al testing

Si tuvieras que elegir qué testear con recursos limitados, el principio de Pareto es sorprendentemente útil. El 80% de los bugs en producción viene del 20% del código. Y ese 20% suele ser predecible.

Lógica de negocio con condicionales complejos. Si una función tiene tres ifs anidados con diferentes caminos posibles, es candidata a test. Si es un getter que devuelve un campo, probablemente no.

Integraciones con servicios externos. Pasarelas de pago, APIs de terceros, servicios de email. Cualquier punto donde tu código habla con otro sistema es una fuente probable de fallos. Los tests aquí no necesitan llamar al servicio real (usa mocks), pero sí verificar que tu código maneja bien las respuestas esperadas y los errores.

Transformaciones de datos. Funciones que reciben datos en un formato y los devuelven en otro son candidatas naturales a tests unitarios. Un serializer de Django que transforma un objeto en JSON para la API, un parser que procesa un CSV de importación, una función que calcula un precio con descuentos acumulados.

Flujos críticos de usuario. Lo que el usuario hace más (login, compra, registro, búsqueda) merece al menos un test de integración que verifique el flujo completo. No hace falta simular el navegador: en Django, el test client te permite hacer peticiones HTTP al servidor de test y verificar respuestas sin salir de pytest.

Lo que probablemente no necesitas testear: código de presentación puro (estilos, layouts), configuraciones triviales, migraciones de base de datos y código generado automáticamente. No porque no puedan fallar, sino porque el coste de mantener esos tests supera el beneficio que aportan.

Tests que restan en vez de sumar

No todos los tests hacen tu proyecto más fiable. Algunos lo hacen más lento, más frágil y más difícil de cambiar. Reconocerlos es tan importante como escribir los buenos.

Tests frágiles. Un test que falla cada vez que cambias un detalle de implementación (el orden de un JSON, el texto exacto de un mensaje, la posición de un elemento en pantalla) genera ruido. El equipo empieza a ignorar los fallos del pipeline porque "seguro que es ese test que siempre falla". Cuando un test frágil falla de verdad, nadie le hace caso.

Tests lentos sin justificación. Un test unitario que tarda más de un segundo tiene un problema. Un suite de tests que tarda 20 minutos en pasar hace que el equipo evite ejecutarlos en local y dependa exclusivamente del CI. Eso ralentiza el ciclo de feedback y frena el desarrollo. En un proyecto Django, si los tests tardan más de un par de minutos, revisa si estás usando la base de datos donde podrías usar mocks.

Tests duplicados. Tres tests que verifican lo mismo de tres formas diferentes no te dan tres veces más confianza. Te dan un test de confianza y dos de mantenimiento. Si cambias la lógica, tienes que actualizar tres tests en vez de uno.

Tests que testean el framework. Verificar que Django devuelve un 404 cuando la URL no existe es testear Django, no tu código. Verifica tu lógica, no la del framework. El equipo de Django ya tiene sus propios tests para eso.

La señal de que tu suite de tests tiene problemas no es que los tests fallen. Es que el equipo no confía en ellos. Si alguien dice "eso seguro que es un falso positivo", tienes un problema más grave que un bug en producción.

El testing como inversión, no como obligación

Hay una forma útil de pensar en el testing: como una póliza de seguro. Pagas un coste ahora (tiempo de desarrollo) para evitar un coste mayor después (bugs en producción, rollbacks, usuarios enfadados, pérdida de ingresos).

Como todo seguro, tiene sentido proporcionar la inversión al riesgo. No aseguras tu bicicleta con la misma póliza que tu casa. No testeas un formulario de contacto con la misma exhaustividad que un sistema de pagos.

Según el informe DORA State of DevOps, los equipos con prácticas de testing sólidas despliegan con más frecuencia y tienen tasas de fallo más bajas. No porque tengan más tests, sino porque los tests que tienen están en los sitios correctos. El testing bien dirigido permite moverse más rápido, no más lento.

Si tu equipo siente que los tests lo ralentizan, el problema no es el testing. Es que estáis testeando las cosas equivocadas, en el lugar equivocado o con herramientas que no encajan.

Por dónde empezar si hoy no tienes casi nada

Si tu proyecto tiene pocos o ningún test, la tentación es "hacer un sprint de testing" para ponerse al día. No lo hagas. Eso genera tests mediocres escritos con prisa que nadie va a mantener.

En lugar de eso, adopta una regla simple: cada bug que llega a producción genera un test antes de arreglarse. Primero reproduces el fallo con un test automatizado. Después lo corriges. Así, tu suite de tests crece de forma orgánica, enfocada exactamente en los problemas reales de tu proyecto.

Empieza por los flujos que te dan más miedo tocar. Esas partes del código donde todo el equipo dice "cuidado con eso". Ahí es donde un par de tests de integración cambian la vida. En un proyecto Django con Wagtail, puede ser el flujo de publicación de contenido. En una app Flutter, el flujo de login o el de compra in-app.

Integra los tests en tu pipeline de CI desde el primer día. Un test que solo se ejecuta en local no existe en la práctica. Cuando los tests se ejecutan en cada push, el equipo los toma en serio.

Y lo más importante: no midas tu progreso en porcentaje de cobertura. Mídelo en confianza. ¿Tu equipo despliega un viernes por la tarde sin nervios? Si la respuesta es sí, probablemente tu testing es suficiente. Si la respuesta es no, ya sabes por dónde empezar.