Pruebas automatizadas para CI/CD

Las pruebas automatizadas son una de las piedras angulares de la integración y la implementación continuas. Al incorporar las pruebas continuas en sus procesos de DevOps, puede mejorar enormemente la calidad de su software.

La integración y la implementación continuas (CI/CD) están concebidas para entregar cambios frecuentes e incrementales, de modo que pueda obtener información sobre su producto o servicio regularmente. Sin embargo, entregar más rápido y con mayor frecuencia no debería reducir la calidad del producto. 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 pruebas automatizado fiable y exhaustivo que le haga confiar en su última compilación es esencial para sus prácticas de CI/CD.

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

Las pruebas son esenciales para asegurar la calidad del software y forman parte de las prácticas de desarrollo de software desde hace mucho tiempo.

En un contexto en cascada, las pruebas manuales o la etapa de aseguramiento de la calidad tienen lugar después de que el código se hubiese desarrollado e integrado.

💡Nota: La estrategia en cascada ―a menudo conocida como el modelo en cascada― es un enfoque linear y secuencial para el desarrollo de software y la gestión de proyectos. Es uno de los primeros modelos utilizados para el desarrollo de software y se caracteriza por un flujo estructurado y sistemático a través de fases distintas.

Un inconveniente de esto es que no puede verificar que su código funcione como se pretende hasta mucho tiempo después de haberlo escrito. Para entonces, es posible que se haya añadido mucho más código sobre él, lo que hace que sea mucho más difícil solucionar cualquier problema. A su vez, esto ralentiza la entrega de nuevas funcionalidades y la corrección de errores.

En cambio, un enfoque Agile favorece ciclos de desarrollo cortos e iterativos para que pueda lanzar más frecuente, recibir comentarios de sus usuarios y tomar decisiones informadas sobre qué compilar a continuación. El CI/CD apoya esta forma de trabajar al automatizar los pasos entre la escritura de su código y el lanzamiento a los usuarios, lo que hace que todo el proceso sea más fiable y eficiente.

Para tener éxito con esta metodología DevOps, necesita confirmar, compilar y probar los cambios de código regularmente, idealmente varias veces al día. Sin embargo, incluso en un equipo pequeño, realizar un conjunto completo de pruebas manuales una vez al día o más no es realista. Por eso las pruebas automatizadas son una parte esencial de cualquier proceso de CI/CD.

Aunque escribir pruebas automatizadas implica una inversión de tiempo por anticipado, el trabajo se rentabiliza tan pronto como los miembros de su equipo comiencen a confirmar y a publicar los cambios con más frecuencia. Invertir en pruebas automatizadas ofrece varios beneficios clave, entre los que se incluyen los siguientes:

  • Cada cambio de código se verifica para asegurarse de que funcione como se espera y no haya introducido nuevos errores.
  • La retroalimentación se entrega más rápido que cuando se realizan las pruebas equivalentes manualmente.
  • Solucionar errores poco después de haberse introducido tiende a ser más eficiente, ya que recuerda bien los cambios y no se ha compilado nada más sobre ellos.
  • Los resultados de las pruebas son más fiables que al realizar las pruebas manualmente, ya que pedirle a alguien que realice la misma tarea con mucha frecuencia inevitablemente resulta en errores e incoherencias.
  • Las pruebas automatizadas pueden ejecutarse en paralelo, de modo que puede escalar su control de calidad (hasta donde lo permita su infraestructura) cuando el tiempo apremia.

Aunque la automatización de pruebas elimina muchas tareas aburridas y repetitivas, eso no hace que sus ingenieros de control de calidad se vuelvan innecesarios. 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 de control de calidad 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?

Las pruebas automatizadas tienen lugar en varias etapas a lo largo del proceso.

El CI/CD y la automatización de control de calidad se centran en crear ciclos de retroalimentación cerrados que permiten a su equipo descubrir 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 una herramienta para priorizar las pruebas automatizada 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 unidad en la base, las pruebas de servicio en el centro y las pruebas de IU en la parte superior.

La pirámide de pruebas consiste en los siguientes pasos:

  • Comience con unos cimientos fuertes de pruebas de unidad automatizadas que son rápidas y fáciles de ejecutar.
  • Luego, pase a las pruebas que son más complejas de escribir y tardan más en ejecutarse.
  • Termine 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. Por ejemplo, si estuviera compilando una aplicación meteorológica, convertir valores de grados Celsius a Fahrenheit podría ser parte de una función más amplia. Puede utilizar pruebas de unidad para verificar que la función de conversión de temperatura devuelve los resultados esperados para un rango de valores. Cada vez que cambia un trozo de código relacionado, puede utilizar estas pruebas de unidad para confirmar que este aspecto en particular funciona según lo previsto sin necesidad de compilar y ejecutar la aplicación cada vez.

En los equipos que hayan decidido invertir en escribir pruebas de unidad, los desarrolladores suelen responsabilizarse de añadirlas a medida que escriben el código relacionado. El desarrollo guiado por pruebas (DGP) consagra este proceso (como explicaremos más adelante), pero el DGP no es un requisito para escribir pruebas de unidad.

Otro enfoque es establecer que las pruebas de unidad forman parte de la definición de «hecho» para cada tarea de desarrollo y verificar que estas pruebas estén presentes al realizar las revisiones de código o al utilizar informes de cobertura de código.

Si está trabajando en un sistema existente y no ha invertido previamente en pruebas de unidad, escribir las pruebas de unidad para toda su base de código desde cero puede parecer una barrera insuperable. Aunque se recomienda una amplia cobertura con pruebas de unidad, puede comenzar con lo que tenga e ir ampliando con el tiempo.

Si su código actualmente no tiene una buena cobertura de prueba de unidad, considere aumentarla estableciendo con su equipo la incorporación de pruebas a cualquier trozo de código que modifique. Esta estrategia asegura que todo el código nuevo esté cubierto y prioriza el código existente en función de aquello con lo que más interactúa.

Pruebas de integración

Con las pruebas de integración, se asegura de que las interacciones entre varias partes de su software, como entre el código de la aplicación y una base de datos o las llamadas a una API, funcionen como se espera.

Puede resultar útil subdividir las pruebas de integración entre pruebas más amplias y pruebas más limitadas. Con el enfoque limitado, la interacción con otro módulo se comprueba utilizando un doble para pruebas en lugar del módulo real. Las pruebas de integración amplias utilizan el componente o servicio real. Si volvemos al ejemplo de una aplicación meteorológica, una prueba de integración amplia podría obtener datos del pronóstico de una API, mientras que una prueba limitada utilizaría datos simulados.

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. Estas se ejecutarán más rápidamente que las pruebas de integración amplias (y proporcionan retroalimentación más rápida), puesto que no requieren que otras partes del sistema estén disponibles.

Si las pruebas limitadas se finalizan correctamente, puede proceder a ejecutar un conjunto de pruebas de integración amplias. Ya que estas pruebas tardan más en ejecutarse y se requiere más esfuerzo para mantenerlas, puede que quiera limitarlas a áreas de mayor prioridad de su producto o servicio.

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. Por lo general, se utilizan para validar casos de uso del negocio, como si un usuario puede crear una cuenta o completar una transacción.

Aunque las pruebas automatizadas de extremo a extremo pueden realizarse a través de una GUI, no tienen por qué; una llamada de API también puede accionar varias partes del sistema (aunque las API también pueden verificarse 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 alterarlas, lo cual da lugar a un ruido inútil en los resultados de su prueba de compilación y a retrasos adicionales en su actualización. Por ello, conviene diseñar las pruebas de extremo a extremo cuidadosamente, y comprendiendo qué es lo que ya han cubierto las pruebas de menor nivel, para que estas sean lo más útiles posible.

Desarrollo guiado por comportamiento

El desarrollo guiado por comportamiento (DGC) es un enfoque colaborativo para el desarrollo de software que cierra la brecha de comunicación entre desarrolladores, testers y partes interesadas de la empresa. Extiende el desarrollo guiado por pruebas al destacar el comportamiento del software en lugar de su implementación.

El DGC puede proporcionar una estrategia útil para desarrollar tanto pruebas de integración como pruebas de extremo a extremo. Estos son algunos de sus aspectos clave:

  • Enfoque en el comportamiento: El DGC se centra en especificar el comportamiento de un sistema a través de ejemplos en lenguaje sencillo. Estos ejemplos suelen escribirse en un formato «Given-When-Then» (dado-cuando-entonces) para escribir el estado inicial, la acción y el resultado esperado.
  • Colaboración: El DGC fomenta la colaboración entre desarrolladores, testers y partes interesadas de la empresa para garantizar que todos comprenden los requisitos. Este proceso colaborativo ayuda a aclarar las expectativas y reducir malentendidos.
  • Especificaciones ejecutables: Los escenarios de DGC se escriben de manera que puedan ejecutarse automáticamente como pruebas. Las herramientas como Cucumber, SpecFlow y JBehave se utilizan habitualmente para escribir estos escenarios en un formato legible para las personas que es posible vincular con pruebas automatizadas.
  • Documentación: Los escenarios sirven tanto de documentación como de pruebas, y proporcionan una especificación clara y representativa del comportamiento del sistema. Esto le permite comprender mejor el sistema y sus requisitos.
  • Desarrollo iterativo: El DGC apoya el desarrollo iterativo e incremental al fomentar la retroalimentación y las mejoras continuas. Cada iteración implica escribir e implementar nuevos escenarios, con el fin de garantizar que el software evolucione de acuerdo con las necesidades de la empresa.

Pruebas de rendimiento

Aunque la pirámide de pruebas no hace referencia a las pruebas de rendimiento, vale la pena considerarlas, 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 verifican cómo se comporta el sistema cuando aumenta la demanda.
  • Las pruebas de estrés superan deliberadamente el uso esperado.
  • Las pruebas de inmersió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 soportará los parámetros definidos, sino también comprobar cómo se comporta cuando se superan esos 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, es importante que las pruebas se ejecuten siempre del mismo modo. Esto significa asegurarse de que los entornos de pruebas permanezcan coherentes entre ejecuciones y actualizarlos para que se adapten a la producción cuando se apliquen cambios en ella.

Gestionar estos entornos puede llevar mucho tiempo. Automatizar el proceso de creación y eliminación de entornos de preproducción con cada nueva compilación le ahorrará tiempo y garantizará un régimen de pruebas automatizadas coherente y fiable.

¿Cómo admite el desarrollo guiado por pruebas las pruebas automatizadas?

El desarrollo basado en pruebas (TDD) es un enfoque de desarrollo que se originó en la programación extrema (XP). Con el DGP, el primer paso es escribir una lista de casos de prueba para la funcionalidad que desea añadir. Luego toma un caso de prueba cada vez, escribe la prueba (que falla) para él y, a continuación, escribe el código para hacer que la prueba tenga éxito. Finalmente refactoriza el código según sea necesario antes de pasar al siguiente caso de prueba. Este proceso se puede resumir como «Red, green, refactor» (rojo, verde, refactorice) o «Make it work; make it right» (haga que funcione; hágalo bien).

Una de las ventajas principales del DGP es que le obliga a añadir pruebas automatizadas para cualquier nuevo código que escriba. Esto significa que su cobertura de prueba siempre está creciendo, habilitando una retroalimentación rápida y periódica cada vez que cambie su código. Otros beneficios del desarrollo guiado por pruebas incluyen los siguientes:

  • La promoción de un enfoque iterativo. Una vez que haya identificado una lista de pruebas, trabaja en un caso de prueba a la vez, perfeccionando la lista de pruebas sobre la marcha.
  • Fomentar la separación entre la interfaz y la implementación. Seguir el proceso «red, green, refactor» es un aspecto esencial para eso.
  • Recibir retroalimentación inmediata mientras trabaja. No solo valida que su último cambio supere la prueba, sino que también verifica que ninguna otra prueba falle ahora.
  • El mantenimiento del código bien documentado, ya que las pruebas aclaran la intención. A su vez, esto hace que su código sea más fácil de mantener y acelera la incorporación de nuevos miembros del equipo.

El DGP es un modo eficaz de compilar su cobertura de pruebas automatizadas para respaldar su proceso de CI/CD. No obstante, el DGP no es un requisito para una estrategia de DevOps efectiva, y puede mantener altos niveles de cobertura de pruebas automatizadas sin el DGP.

Trabajar con feedback

El propósito de ejecutar pruebas automatizadas como parte de su práctica de CI/CD es recibir una retroalimentación rápida sobre los cambios que acaba de realizar. Escuchar y responder a esa retroalimentación es una parte esencial del proceso. Las siguientes prácticas le ayudarán a obtener el máximo provecho de su régimen de pruebas automatizadas:

  • Haga sus resultados de pruebas fáciles de acceder. Los servidores de integración continua suele integrarse con herramientas de pruebas automatizadas para que pueda revisar todos los resultados en una vista de panel o de radiador.
  • Integre los informes de pruebas con su plataforma de mensajes, como Slack, para recibir notificaciones automatizadas sobre los resultados de las pruebas.
  • Cuando falla una prueba, rastree la causa lo antes posible para que pueda empezar a trabajar en una solución antes de que se compile más código sobre ella. Las herramientas de CI que identifican el área de la base de código que la prueba afecta y proporcionan acceso a cualquier dato producido por ella, como trazas de pila, valores de salida y capturas de pantalla, pueden acelerar este proceso.
  • Diseñe cada prueba para verificar una sola cosa e indique sus pruebas con precisión para que pueda entender fácilmente qué ha fallado.

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.

Pruebas continuas vs. pruebas automatizadas

Para muchos equipos, un punto de partida de las pruebas automatizadas es un conjunto de pruebas de unidad que puede añadir manualmente o como parte de un proceso de integración continua. A medida que su cultura de DevOps madura, puede comenzar a avanzar en la pirámide de pruebas añadiendo pruebas de integración, de extremo a extremo, seguridad, rendimiento y mucho más.

Las pruebas continuas consisten en la práctica de ejecutar una amplia gama de pruebas automatizadas como parte de un proceso de CI/CD. Con las pruebas continuas, cada conjunto de cambios de código se somete automáticamente a una serie de pruebas automatizadas para que cualquier error se descubra lo antes posible.

Las etapas iniciales de un proceso de pruebas continuas puede incluir pruebas ejecutadas en el IDE incluso antes de que los cambios se confirmen. Para las pruebas en etapas posteriores, las pruebas continuas generalmente requieren entornos de prueba que se actualizan automáticamente como parte del proceso.

Un proceso de pruebas continuas totalmente automatizado proporciona la máxima confianza en los cambios del código, al tiempo que acelera los lanzamientos. Al someter su software a un régimen de pruebas riguroso, reduce significativamente el riesgo de errores. Ejecutar ese proceso de manera automática y continua no solo le ayuda a trabajar más eficiente, sino que también le permite implementar correcciones urgentes de manera rápida y fiable.

Aunque las pruebas continuas requieren tiempo para implementarse, es un objetivo al que puede avanzar de manera incremental a medida que automatiza otros aspectos de sus procesos de CI/CD y aumenta la cobertura de sus pruebas.

¿Suponen 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 de pruebas, 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 un enfoque para las pruebas planificado y estructurado haya 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. 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.

Las pruebas exploratorias no debe convertirse en pruebas manuales y repetitivas. La intención no es realizar el mismo conjunto de verificaciones cada vez. Cuando se descubren problemas durante las pruebas exploratorias, es necesario tanto solucionar el problema como escribir una o más pruebas automatizadas. De este modo, si el problema vuelve a ocurrir, se detectará mucho antes en el proceso.

Mejora continua para la automatización de pruebas

Crear un conjunto de pruebas no es algo que se haga una vez y ya pueda olvidarse. Es necesario mantener las pruebas automatizadas para asegurarse de que sigan siendo relevantes y útiles. Así como continúa mejorando su código, también debe seguir mejorando sus pruebas.

Continuar añadiendo 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 las pruebas y si convendría reorganizar o desglosar los pasos del proceso para obtener retroalimentación más rápidamente.

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, debe evitar 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 una retroalimentación rápida y fiable al darle confianza antes de implementar su software a la producción.

Pensamientos finales sobre las pruebas automatizadas para CI/CD

Las pruebas automatizadas desempeñan un papel esencial en cualquier proceso de CI/CD. Ejecutar las pruebas de manera automática proporciona una retroalimentación rápida y fiable sobre los cambios en su código. A su vez, esto hace que el desarrollo sea más eficiente, ya que identificar errores más temprano facilita su corrección.

Es una buena práctica organizar sus pruebas automatizadas según el tiempo que tardan en ejecutarse. Las pruebas de unidad deben ejecutarse primero, ya que proporcionan la retroalimentación más rápida, seguidas de las pruebas de integración y, finalmente, las pruebas de extremo a extremo. Si no dispone de ningunas pruebas automatizadas, las pruebas de unidad son el mejor lugar para empezar. El desarrollo guiado por pruebas (DGP) es una práctica de desarrollo demostrada que le puede ayudar a mejorar y mantener la cobertura de pruebas de unidad.

A medida que su cultura de DevOps madura, es posible que desee pasar a las pruebas continuas. Parte de esta transición implicará automatizar la creación y el mantenimiento de sus entornos de prueba. Al escribir pruebas automatizadas de mayor nivel, considere priorizar las áreas que presentan el mayor riesgo. Esto puede requerir pruebas de rendimiento automatizadas, como pruebas de carga, estrés o inmersión. Las pruebas exploratorias manuales son una buena forma de identificar lagunas en su cobertura de pruebas para que pueda seguir mejorando su proceso de CI/CD.

Cómo puede ayudarle TeamCity

TeamCity ofrece una amplia compatibilidad con marcos de trabajo de prueba y una variedad de funcionalidades de automatización de pruebas para ayudarle a obtener el máximo de su proceso de CI/CD.

La velocidad y la fiabilidad son esenciales para una automatización de pruebas efectiva, y TeamCity está optimizado para ambas. Además de proporcionar informes de las pruebas detallados para ayudarle a llegar al fondo de los problemas más rápidamente, TeamCity automáticamente destaca las pruebas inestables para que pueda asegurarse de que solo se marquen los fallos válidos. La reordenación inteligente de pruebas y la paralelización ofrecen resultados aún más rápidos, mientras que la funcionalidad de ejecución remota proporciona la retroalimentación antes de confirmar.

Dado que TeamCity ofrece integraciones con sistemas de seguimiento de incidencias, IDE, Slack y otras plataformas, puede recibir notificaciones sobre las pruebas falladas independientemente de dónde esté trabajando. Finalmente, la compatibilidad total con máquinas virtuales y contenedores Docker le permite automatizar la gestión de sus entornos de prueba e implementar pruebas continuas como parte de su proceso de CI/CD.