Pruebas automatizadas para CI/CD

El objetivo de la integración y la implementación continuas (CI/CD) es permitir que los equipos de desarrollo puedan hacer llegar a los usuarios un software funcional, para así entregar valor y obtener feedback útil sobre cómo se utiliza su producto en el mundo real. Muchas organizaciones han adoptado las prácticas de DevOps (Desarrollo y operaciones) como un modo de mantenerse al día con la competencia.

No obstante, la presión empresarial de entregar más rápido no debería reducir la calidad de lo que se está produciendo. Después de todo, sus usuarios esperan un software estable y funcional, incluso aunque siempre estén ávidos de novedades. Por eso, un proceso de testeo automatizado fiable y en profundidad que le haga confiar en su última compilación es esencial para su práctica de integración y entrega continuas.

¿Por qué deberían automatizarse las pruebas de CI/CD?

Las pruebas son esenciales para asegurar la calidad del software y durante mucho tiempo han formado parte de las prácticas de desarrollo de software.

En un contexto en cascada, las pruebas manuales o la etapa de aseguramiento de la calidad tenían lugar después de que el código se hubiese desarrollado e integrado, y el objetivo era comprobar si la aplicación se comportaba según las especificaciones.

Este enfoque lineal ralentiza el proceso de lanzamiento y significa que sus desarrolladores no pueden comprobar que lo que se ha creado funciona como debería hasta mucho más adelante, cuando se haya dedicado mucho más tiempo a ampliarlo. En contraste, un proceso de automatización de CI/CD permite un enfoque ágil de ciclos iterativos y breves que ofrezcan un feedback rápido y permitan que las actualizaciones se lancen poco a poco y a menudo. Una pieza clave de estos ciclos breves e iterativos es testear para validar automáticamente que el código nuevo funciona y no ha estropeado nada más.

La integración continua implica confirmar cambios de código a la rama principal o tronco con regularidad, desencadenar una compilación si es aplicable y asegurar la calidad del software cada vez. Para disfrutar realmente de las ventajas de la integración continua, los miembros de su equipo deberían tratar de confirmar cambios al menos diariamente. No obstante, incluso en un equipo pequeño, realizar este nivel de testeo de la automatización de forma manual supondría una exigencia considerable para los ingenieros de control de calidad e implicaría un trabajo muy repetitivo. Aquí es donde entran en acción las pruebas automatizadas.

Las pruebas automatizadas son ideales para las tareas repetitivas y logran resultados más coherentes que el proceso manual, ya que a las personas se les pueden escapar detalles o realizar comprobaciones de forma incoherente cuando se les pide que sigan los mismos pasos una y otra vez.

Además de ser más rápidas que ejecutar las pruebas equivalentes manualmente, las pruebas automatizadas pueden ejecutarse en paralelo, de modo que puede escalar el control de calidad (hasta donde lo permita su infraestructura) cuando el tiempo apremia. Aunque escribir pruebas automatizadas implica una inversión de tiempo por anticipado, se rentabiliza tan pronto como los miembros de su equipo comiencen a confirmar los cambios con regularidad y a lanzar para la producción con mucha más frecuencia.

Aunque las pruebas automatizadas eliminan muchas tareas aburridas y repetitivas, eso no hace que sus ingenieros de control de calidad queden obsoletos. Además de definir y priorizar casos relacionados, el equipo de control de calidad participa en la redacción de pruebas automatizadas, a menudo en colaboración con los desarrolladores. Los ingenieros también son necesarios para las partes que no pueden automatizarse, como comentaremos más adelante.

¿Qué lugar ocupan las pruebas en el proceso de CI/CD?

La respuesta es que las pruebas tienen lugar en múltiples etapas a lo largo del proceso.

Si es usted nuevo en la integración y la implementación continuas, esto podría sonar excesivo, pero la CI/CD y automatización de control de calidad se trata de bucles de feedback breves que permiten que su equipo detecte los problemas lo antes posible.

Es mucho más fácil solucionar un problema poco después de que surja, puesto que evita que se escriba más código sobre unos fundamentos incorrectos. También es más eficiente para su equipo realizar cambios antes de pasar a lo siguiente y perder el contexto.

Muchas herramientas de pruebas de compilación automatizadas admiten la integración con herramientas de CI/CD, para que pueda introducir los datos de prueba en el proceso y ejecutar las pruebas en etapas, con resultados tras cada paso. Dependiendo de su herramienta de integración continua, también puede escoger si desea trasladar una compilación a la siguiente etapa basándose en el resultado de las pruebas del paso anterior.

Para sacar el máximo partido a su proceso a través de las pruebas automatizadas, normalmente tiene sentido organizar sus pruebas de compilación de modo que las más rápidas se ejecuten primero. Esto le da feedback más pronto y logra un uso más eficiente de los entornos de pruebas, puesto que puede asegurarse de que se han pasado las pruebas iniciales antes de ejecutar otras más prolongadas y complejas.

Al considerar cómo priorizar la creación y la ejecución de pruebas automatizadas, resulta útil pensar en la pirámide de pruebas.

Crear una pirámide de pruebas

La pirámide de pruebas es un modo práctico de conceptualizar cómo priorizar las pruebas de integración automatizadas en un proceso de CI/CD, tanto en cuanto al número relativo como al orden en que se ejecutan.

Originalmente definida por Mike Cohn, la pirámide de pruebas muestra las pruebas de unidades en la base, las pruebas de servicio en el centro y las pruebas de IU en la parte superior.

Aunque puede que su nomenclatura no sea precisa, la premisa está clara: comenzar con unos cimientos fuertes de pruebas de unidades automatizadas que son rápidas y fáciles de ejecutar, antes de pasar a las pruebas que son más complejas de escribir y tardan más en ejecutarse, y terminar con un pequeño número de las pruebas más complejas. ¿Qué tipos de pruebas de CI/CD debería plantearse? Examinemos las opciones.

Pruebas de unidad

Las pruebas de unidades constituyen acertadamente la base de la pirámide de pruebas. Estas están diseñadas para asegurarse de que su código funcione como espera abordando la unidad de comportamiento más pequeña posible. En los equipos que hayan decidido invertir en escribir pruebas de unidades, los desarrolladores suelen responsabilizarse de escribirlas a medida que escriben el código. Esto se hace automáticamente al practicar un desarrollo basado en pruebas (TDD, del inglés Test Driven Development). Pero el TDD no es un requisito para escribir pruebas de unidades.

Si está trabajando en un sistema existente y no ha invertido previamente en pruebas de unidades, escribirlas para toda su base de código desde cero suele ser una barrera insuperable. Mientras que se recomienda una amplia cobertura con pruebas de unidades, puede comenzar con lo que tenga e ir ampliando con el tiempo. Una estrategia realista puede ser añadir pruebas de unidades a cualquier fragmento de código que toque, y asegurarse así de que todo código nuevo queda cubierto, y priorizando el código existente según con qué interactúe durante el desarrollo.

Pruebas de integración

Con las pruebas de integración, se asegura de que múltiples partes de su software interactúan entre sí tal y como se espera, como la interacción entre cierto código de la aplicación y una base de datos. Puede resultar útil subdividir las pruebas de integración entre pruebas más amplias y pruebas más limitadas. Con las pruebas de integración limitadas, la interacción con otro módulo se comprueba utilizando un doble para pruebas, en lugar del módulo real, mientras que unas pruebas de integración amplias utilizan el componente o servicio real.

Dependiendo de la complejidad de su proyecto y del número de servicios internos y externos implicados, quizá desee escribir una capa de pruebas de integración limitadas que se ejecutarán más rápidamente que las pruebas de integración amplias (puesto que no requieren que otras partes del sistema estén disponibles) y, a continuación, efectuar una serie de pruebas de integración amplias, que potencialmente se dirijan a áreas prioritarias de su sistema.

Pruebas de extremo a extremo

También conocidas como pruebas completas o full-stack, las pruebas de extremo a extremo revisan la aplicación completa. Aunque estas pruebas pueden realizarse a través de la GUI, no tienen por qué; una llamada de API también puede accionar múltiples partes del sistema (aunque las API también pueden testearse con pruebas de integración). La pirámide de pruebas recomienda emplear un menor número de estas pruebas, no solo porque se tarda más en ejecutarlas, sino porque tienden a ser frágiles.

Cualquier cambio en la interfaz del usuario puede alterar estas pruebas, lo cual da lugar a un ruido inútil en los resultados de su prueba de compilación y a retrasos en su actualización. Conviene diseñar las pruebas de extremo a extremo cuidadosamente, y comprendiendo qué es lo que ya han cubierto las pruebas de compilación de menor nivel, para que estas sean lo más útiles posible.

Pruebas de rendimiento

Aunque la pirámide de pruebas no hace referencia a las pruebas de rendimiento, vale la pena plantearse incluirlas en su conjunto de pruebas automatizadas, especialmente para productos en los que la estabilidad y la velocidad son requisitos clave.

Bajo la denominación general de "pruebas de rendimiento" se incluye toda una serie de estrategias de pruebas diseñadas para comprobar cómo se comportará el software en un entorno real. Las pruebas de carga comprueban cómo se comporta el sistema cuando aumenta la demanda, mientras que las pruebas de estrés superan deliberadamente el uso esperado y las pruebas de asimilación (o de resistencia) miden el rendimiento bajo una alta carga continuada.

Con estos tipos de pruebas, el objetivo no es solo confirmar que el software funcionará con los parámetros definidos, sino también comprobar cómo se comporta cuando se superan estos parámetros, idealmente fallando con dignidad en lugar de arder en llamas.

Entornos de pruebas

Tanto las pruebas de rendimiento como las de extremo a extremo requieren entornos similares a los de producción, y pueden necesitar datos de pruebas de compilación. Para que un régimen de pruebas automatizadas ofrezca confianza en el software que se está probando, es importante que las pruebas de compilación se ejecuten siempre del mismo modo, y ello incluye asegurarse de que los entornos de pruebas permanecen coherentes entre ejecuciones (aunque deberían actualizarse para adaptarse a la producción cuando se apliquen cambios en ella).

Gestionar los entornos manualmente puede ser una tarea laboriosa, de modo que vale la pena pensar en automatizar los pasos para crear y desglosar entornos de preproducción con cada nueva compilación.

Trabajar con feedback

El objetivo de ejecutar pruebas automatizadas como parte de su CI/CD es obtener feedback rápido acerca de los cambios que acaba de realizar, así que es esencial escuchar y responder a ese feedback.

Los servidores de integración continua suelen integrarse con herramientas de pruebas automatizadas para que pueda visualizar todos los resultados en un solo lugar. Los equipos de desarrollo suelen combinar una vista de panel o de radiador de los últimos resultados con las notificaciones automatizadas en plataformas de comunicación, como Slack, para mantenerse informados sobre cómo está funcionando la última compilación.

Cuando una prueba falla, comprender con qué área de la base de código está relacionada la prueba y ser capaz de ver cualquier información creada por la prueba, como un stacktrace, valor de salida o una captura de pantalla, puede acelerar el proceso de llegar a la causa raíz. Vale la pena tomarse su tiempo para diseñar las pruebas con atención, para que cada una compruebe una sola cosa, y etiquetarlas específicamente para poder comprender qué ha fallado. Las herramientas de CI y de pruebas de integración continua que ofrecen información adicional acerca de fallos en las pruebas también pueden ayudarle a devolver las compilaciones al buen camino lo antes posible.

Como siempre, las herramientas y prácticas solo son una parte de la ecuación. Una automatización de CI/CD realmente buena requiere una cultura de equipo que reconozca no solo el valor de las pruebas de CI/CD automatizadas, sino también la importancia de responder a las pruebas fallidas con rapidez para mantener el software en un estado implementable.

¿Es el CI/CD y las pruebas automatizadas el fin de las pruebas manuales?

Un malentendido habitual entre los recién llegados a la CI/CD es que las pruebas automatizadas anulan la necesidad de pruebas manuales y de ingenieros de control de calidad profesionales.

Aunque la automatización de CI/CD deja algo más de tiempo libre a los miembros del equipo de calidad, no les sustituye. En lugar de perder tiempo en tareas repetitivas, los ingenieros pueden centrarse en definir casos relativos, escribir pruebas automatizadas y aplicar su creatividad y su ingenio a las pruebas exploratorias.

A diferencia de las pruebas de compilación automatizadas, que requieren una cuidadosa elaboración de scripts para su ejecución por parte de un ordenador, las pruebas exploratorias solo requieren una base más ligera. El valor de las pruebas exploratorias es encontrar cosas que las pruebas planificadas y estructuradas hayan obviado. Básicamente, buscan incidencias que todavía no se había planteado y para las que no había escrito pruebas. Al decidir qué áreas explorar, piense tanto en las nuevas funcionalidades como en áreas de su sistema que causarían más daños si algo fuese mal en la producción.

Las pruebas exploratorias no deberían convertirse en pruebas manuales y repetitivas; la intención es no llevar a cabo el mismo grupo de pruebas cada vez. Cuando se detectan incidencias durante las pruebas exploratorias, además de resolverlas, tómese su tiempo para escribir una prueba automatizada, de modo que si vuelve a suceder se detecten en una etapa mucho más inicial del proceso. Para hacer un uso eficiente del tiempo de los testers, las pruebas manuales solo deberían llevarse a cabo una vez superadas todas las pruebas automatizadas.

Mejora continua para la automatización de pruebas

Las pruebas automatizadas desempeñan un papel esencial en el proceso de CI/CD.

Aunque escribir pruebas automatizadas requiere invertir tiempo y esfuerzo, las ventajas de un feedback rápido y de ver lo implementable que es el código hacen que las pruebas automatizadas pronto den sus frutos. Pero crear un conjunto de pruebas no es algo que se haga una vez y ya puede olvidarse.

Sus pruebas de compilación automatizadas deberían formar parte de su aplicación igual que lo hace el resto de su código, y con ello requerirían un mantenimiento que le asegure que continúan siendo relevantes y útiles. Por lo tanto, la mejora continua que aplica a su código también se aplica a sus pruebas.

Continuar creando cobertura de pruebas automatizadas para nuevas funcionalidades e incorporar lo detectado en las pruebas exploratorias mantendrá su conjunto de pruebas eficaz y eficiente. También vale la pena tomarse su tiempo para ver cómo están funcionando, y si convendría reorganizar o desglosar los pasos de su trabajo para obtener feedback con mayor rapidez.

Las herramientas de integración continua pueden proporcionarle varias métricas que le ayudarán a optimizar su proceso, mientras que los indicadores de pruebas poco fiables marcarán las pruebas que puedan ofrecerle una falsa confianza o motivo de preocupación. Pero, mientras que las métricas pueden ayudarle a mejorar su proceso de pruebas automatizadas, evite caer en la trampa de pensar que la cobertura de pruebas es un objetivo en sí mismo. El verdadero objetivo es entregar con regularidad software funcional a sus usuarios. La automatización contribuye a ese objetivo dándole un feedback rápido y fiable para que pueda implementar su software a la producción con confianza.