Wednesday, June 11, 2025

Cuando el código funciona, pero no tiene tests: ¿y ahora qué?

Seguramente te ha pasado alguna vez. Te dan acceso al repositorio de un nuevo proyecto. Lo abres con curiosidad, esperas encontrar una estructura bien organizada, quizás alguna carpeta de tests. Comienzas a revisar los archivos y, para tu sorpresa, no hay ni una sola prueba. Ni unitarias. Ni de integración. Ni siquiera una prueba olvidada en un rincón del código. Nada. Pero lo más curioso es que ese sistema lleva tres años en producción. Funciona. Se usa a diario. Y sin embargo, todos en el equipo le tienen miedo. Nadie quiere tocar nada porque el más mínimo cambio puede romper algo importante… y nadie sabría con certeza qué fue.

Frente a este escenario, la pregunta es inevitable: ¿por dónde empiezo? ¿Cómo puedo empezar a testear sin volverme loco ni romper lo que ya está funcionando? Esta duda no solo la tienen los desarrolladores que recién se suman a un proyecto. Muchas empresas se enfrentan a este dilema en algún momento de su vida tecnológica. Y aunque cada contexto tiene sus particularidades, la respuesta de fondo suele ser la misma: si no puedes testear, probablemente es porque el código no fue diseñado para ser testeado.

Esto es algo más común de lo que parece. Cuando un sistema crece sin una estrategia clara de pruebas, lo que suele pasar es que se acumula lo que se conoce como complejidad accidental. Hay demasiado acoplamiento entre clases y módulos, poca cohesión interna, muchas responsabilidades mezcladas en los mismos componentes. El código se vuelve rígido, difícil de dividir y casi imposible de probar en pequeñas unidades. Y aquí viene una verdad incómoda: no hay atajos mágicos que te permitan hacer testing si el diseño del sistema no lo permite. Puedes intentarlo, claro, pero es como querer medir la temperatura con una regla: simplemente no va a funcionar.

Entonces, ¿qué hacer en estos casos? La mejor forma de empezar es con pruebas de extremo a extremo, también conocidas como tests end-to-end (E2E). Estas pruebas se enfocan en validar que el sistema funciona correctamente desde el punto de vista del usuario, sin importar cómo está construido por dentro. Piensa en ellas como una caja negra: no necesitas saber cómo están organizadas las clases, qué métodos se llaman, ni qué librerías usa el sistema. Solo te importa que, si ingresas ciertos datos por la interfaz, el resultado sea el esperado.

Los tests end-to-end te dan una ventaja enorme al inicio. Aunque suelen ser más lentos y costosos de mantener, en este contexto cumplen una función clave: crear una red de seguridad. Con ellos puedes detectar si rompiste algo importante al hacer un cambio. Te dan confianza para empezar a refactorizar, para mover piezas internas del sistema sin miedo a dejarlo inutilizable.

Una vez que tienes esa base de pruebas automáticas funcionando, el siguiente paso es comenzar a mejorar el diseño del sistema. No hace falta reescribir todo desde cero. De hecho, eso sería un error. Lo que sí puedes hacer es aplicar pequeñas mejoras: dividir responsabilidades, separar lógicas en distintas clases, introducir interfaces, eliminar dependencias directas, aplicar patrones de diseño donde tenga sentido. Estos cambios van haciendo que el código se vuelva cada vez más modular, más limpio… y, lo más importante, más testeable.

Cuando alcanzas un punto en el que puedes aislar comportamientos o componentes, entonces puedes empezar a escribir pruebas unitarias y de integración. Estos tipos de tests son más rápidos, más baratos de mantener, y te permiten obtener feedback casi inmediato. Ya no necesitas levantar toda la aplicación para probar algo; basta con ejecutar unos pocos tests y ver si todo sigue en orden. Este es el momento en el que verdaderamente comienza a cambiar la cultura del proyecto: pasas de tener miedo a tocar el código, a tener confianza para mejorarlo continuamente.

En resumen, no hay más ciencia que esta: empieza por donde puedas, construye una base segura con pruebas de extremo a extremo, refactoriza con cuidado hacia un diseño más limpio, y luego introduce tests más pequeños y específicos. Es un camino gradual, pero muy poderoso. No se trata de hacer testing por cumplir, sino de transformar la forma en que desarrollas y mantienes el software.

Así que si estás frente a un proyecto sin pruebas y con años de historia encima, no te frustres. No estás solo. Muchos hemos estado ahí. Empieza poco a poco, con paciencia, y verás cómo el sistema se vuelve cada vez más mantenible… y tú, cada vez más tranquilo al trabajar en él.

Cuando el código funciona, pero no tiene tests: ¿y ahora qué?

Seguramente te ha pasado alguna vez. Te dan acceso al repositorio de un nuevo proyecto. Lo abres con curiosidad, esperas encontrar una estru...