Pruebas de utilidades de línea de comandos

Rate this content
Bookmark

¿Alguna vez te has preguntado cuál es la mejor manera de probar tus utilidades de línea de comandos personalizadas? En esta charla, Florian Rappl te dará algunas ideas sobre lo que puedes hacer para verificar automáticamente tus herramientas CLI y evitar regresiones.

- Introducción: ¿Por qué probar las herramientas CLI?

- Desafíos: Contaminación del sistema de archivos, problemas de red y base de datos, variables de entorno

- Demostración: Mostrar problemas con una herramienta CLI de demostración - Soluciones: Implementación del plan de pruebas, elección del nivel adecuado de contenerización

- Demostración: Mostrar la solución utilizando la herramienta CLI anterior

- Conclusión

34 min
03 Nov, 2022

Video Summary and Transcription

Las utilidades de línea de comandos son importantes de probar porque actúan como un punto de intersección entre diferentes partes de una aplicación. El principal desafío en la prueba de utilidades de línea de comandos es el rendimiento, que se puede mejorar mediante el uso de directorios temporales. La gestión de puertos y recursos es crucial para evitar conflictos al ejecutar múltiples conjuntos de pruebas. El contexto de prueba garantiza que los procesos se ejecuten en el contexto correcto, incluido el uso de los directorios correctos. Ejecutar pruebas en diferentes configuraciones ayuda a identificar problemas de compatibilidad y proporciona una cobertura de prueba integral.

Available in English

1. Introducción a la Prueba de Utilidades de Línea de Comandos

Short description:

Bienvenidos a la sesión, Prueba de Utilidades de Línea de Comandos. Las utilidades de línea de comandos son importantes de probar porque actúan como un punto de intersección entre diferentes partes de una aplicación. Pueden acceder a recursos de red e interactuar con el sistema localmente, lo que requiere una coordinación adecuada y un entorno controlado. Estos desafíos hacen que las utilidades de línea de comandos sean particularmente interesantes para la prueba. Por ejemplo, PyCLI es una utilidad que ayuda con tareas de desarrollo web como la creación de estructuras y la ejecución de procesos de depuración.

Bienvenidos a la sesión, Prueba de Utilidades de Línea de Comandos. Espero que estén tan motivados como yo para comenzar.

Antes de comenzar, echemos un vistazo a mi persona. Hola, soy Florian. Soy un arquitecto de soluciones en una empresa más pequeña con sede en Munich, Alemania, llamada SMAPIOK. Nos dedicamos principalmente a IoT y computación integrada y estamos especializados en proyectos de transformación digital, especialmente en aplicaciones web distribuidas. También soy un entusiasta del código abierto. ¿Qué significa eso? Bueno, he sido galardonado como Microsoft MVP en el área de herramientas de desarrollo durante la última década. Paso la mayor parte de mi tiempo trabajando en proyectos en el espacio de .NET, JavaScript, TypeScript y desarrollo web. Escribo muchos artículos y también he escrito un libro sobre micro frontends y actualmente estoy escribiendo otro libro sobre el desarrollo de aplicaciones frontend con NoJazz, así que asegúrense de conseguir una copia. Pero basta de hablar de mí, vamos directo al tema antes de que se nos acabe el tiempo.

Entonces, ¿qué hace que las utilidades de línea de comandos sean difíciles de probar? ¿Qué hace que también sean atractivas de probar? Bueno, en primer lugar, quiero decir, CLI implica que se ejecutan en la línea de comandos, lo cual es bueno por un lado porque iniciar un proceso de terminal siempre es bastante fácil y en cierto sentido también fácil de trabajar, mucho más fácil que trabajar, por ejemplo, con una interfaz gráfica de usuario. Por otro lado, por supuesto, debes lidiar con algunas cosas como, por ejemplo, recibir la salida estándar o también colocar algunas entradas en el flujo estándar de entrada. Y, por supuesto, necesitas coordinar eso y tener tus procesos asíncronos correctamente. Las utilidades de línea de comandos a menudo proporcionan, digamos, un punto de intersección entre dos partes de una aplicación por lo que son bastante importantes de probar para que funcionen correctamente. Y confiamos mucho en las utilidades de línea de comandos, por lo que tenerlas funcionando de manera confiable siempre es lo que buscamos. De todos modos, estas utilidades de línea de comandos, al igual que cualquier otra aplicación, también pueden acceder a algunos recursos. Por ejemplo, por supuesto, recursos de red. Y sí, quiero decir, es posible que desees simular estos, es posible que necesites ejecutar servicios locales y también puede que necesites coordinar estos recursos. Así que eso es algo que debes tener en cuenta. También, por supuesto, con cada paso que das en una dirección de simulación, por supuesto, eliminas una fuente potencial de error para una ejecución posterior y deberás tenerlo en cuenta. Sin embargo, el área más importante es, por supuesto, lo que sucede localmente en el sistema. Por ejemplo, en el sistema de archivos, las operaciones de lectura y escritura deben estar correctamente aisladas. Si ejecutas especialmente múltiples pruebas en paralelo, no puedes simplemente ir a ciegas y decir lo que hacen estas utilidades que estoy probando es correcto, solo confío en que siempre funcionan en, no sé, directorios dedicados y que no hay condiciones de carrera o lo que sea, realmente ejecutándolos en paralelo. Y eso, por supuesto, se aplica a cualquier tipo de recurso del sistema al que accedan. Ya tenemos un conjunto de desafíos pero también un conjunto de cosas que hacen que las utilidades de línea de comandos sean particularmente interesantes para la prueba.

Muy bien, yendo un poco más allá y pensando en algunos desafíos que surgen en eso, ya hemos hablado sobre la entrada y salida. Servir contenido ya se mencionó brevemente solo para recordarles. Por ejemplo, digamos que lo que vamos a probar es el llamado PyCLI. Es una pequeña utilidad que ayuda con algunas tareas relacionadas con el desarrollo web. Una de ellas es la creación de estructuras, pero otra que harías bastante después de la creación de estructuras es ejecutar, por ejemplo, un proceso de depuración con ella.

2. Verificación de Puerto y Contenido, Manejo de Fragmentación

Short description:

La utilidad de línea de comandos abre un puerto y sirve contenido en ese puerto. Para garantizar la corrección, podemos hacer ping al puerto y usar utilidades como BlayWrite para acceder y verificar el contenido. La fragmentación es un desafío común donde la utilidad coloca contenido en varios directorios. Esto se puede evitar limpiando después de cada prueba y asegurando el aislamiento de las pruebas.

Y este proceso de debug en realidad abre un servidor web en tu máquina local. Ahora queremos, por supuesto, verificar que esto se haya abierto correctamente. Y, por supuesto, esta parte de la CLI que abre algún puerto es algo que debemos tener en cuenta. Ahora, ¿cómo nos aseguramos de que se haya abierto el puerto correcto, pero también, por supuesto, de que el contenido servido en el puerto sea correcto? Necesitas, por supuesto, tener todas esas preguntas respondidas.

En nuestro caso, lo que hicimos, por supuesto, es asegurarnos de tener solo un ping en el puerto, que el puerto esté activo, pero luego, lo que podemos hacer es usar utilidades como BlayWrite para acceder realmente al contenido, leerlo y verificarlo con, digamos, una fuente de expectativa para asegurarnos de que los recursos reservados sean los mismos.

Ahora, la fragmentación es algo que aparecerá con bastante frecuencia, lo que significa que una utilidad de CLI puede, digamos, colocar contenido que, por ejemplo, crea en un par de directorios. Y no quieres que eso suceda tan a menudo, porque en primer lugar, necesitas limpiar después de cada prueba. Y en segundo lugar, necesitas asegurarte de que la prueba, por supuesto, se mantenga aislada, ¿verdad? Que puedas ejecutar, por ejemplo, múltiples casos de prueba en paralelo o múltiples suites de pruebas. Y si no tienes control sobre dónde la utilidad que deseas probar coloca los archivos, podrías encontrarte con estas condiciones de carrera que mencioné anteriormente.

3. Mejorando el rendimiento con directorios temporales

Short description:

El principal desafío en la prueba de utilidades de línea de comandos (CLI) es el rendimiento. Ejecutar múltiples pruebas puede resultar en retrasos inaceptables. Para mejorar el rendimiento, una estrategia es utilizar directorios temporales. Otro enfoque es crear directorios temporales del sistema operativo (OS), lo que te permite definir su ubicación. Sin embargo, el uso de directorios temporales del sistema operativo puede dificultar la ubicación de la salida y la depuración de errores. Una solución más eficiente es crear un directorio de plantilla con todos los pasos necesarios para cada prueba. Cuando se crea una nueva prueba, se crea un directorio temporal como copia de la plantilla. Esto minimiza la sobrecarga y permite que las pruebas se ejecuten de manera eficiente.

Un problema adicional que potencialmente será incluso el principal desafío al que te enfrentarás es el rendimiento. Ahora, si, digamos, ejecutar un caso de prueba lleva, por ejemplo, 30 segundos porque necesitas crear y estructurar muchos archivos, bueno, esto podría ser aceptable si solo tienes una prueba. Pero si tienes 100 pruebas o incluso 1,000, entonces 30 segundos definitivamente no es algo que puedas aceptar. Por lo tanto, debes pensar en cómo puedes mejorar el rendimiento aquí, cómo puedes lograr que, en promedio, quiero decir, tal vez aún haya casos de prueba que lleven más tiempo, pero en promedio, tengas tiempos entre uno y cinco segundos como máximo.

Entonces, debes pensar en cómo estructurar esto de manera realmente eficiente. Y una estrategia es, bueno, utilizar directorios temporales. La parte importante es que estos son directorios que tú crearás. Hay otra estrategia en la que creas directorios temporales del sistema operativo (OS). Estos provienen del sistema operativo. Y la gran diferencia es que cuando los creas, puedes definir dónde se colocan, lo cual tiene mucho sentido. Porque, después de todo, si el sistema operativo decide dónde se aloja este directorio temporal, bueno, quiero decir, en primer lugar, se salen un poco de tu vista, y pueden ser bastante grandes en tamaño. Pero eso puede ser aceptable por un tiempo. Pero peor aún, no ves tan fácilmente dónde se colocó esa salida. Y, por supuesto, por ejemplo, en un escenario de CI/CD, no puedes simplemente, bueno, publicarlos muy fácilmente y luego ver qué estaba sucediendo realmente en ese directorio, por qué falló la prueba o, cuando tuvo éxito, poder verificar manualmente que todas tus, digamos, afirmaciones en la prueba sean realmente útiles y funcionen.

De todos modos, lo que puedes hacer con esto es cuando una prueba comienza, como la prueba uno aquí, simplemente crear este directorio temporal en una ubicación conocida y trabajar en este directorio y estar bien y hacer lo mismo con un segundo directorio, tal vez incluso un tercero. Y hasta ahora parece bastante bien, ¿verdad? Aún necesitas, digamos, algunos elementos básicos a los que siempre te refieres, por supuesto, a este directorio temporal, no solo permitas que la utilidad haga lo que quiera. Por ejemplo, el contexto, el directorio de trabajo, para comenzar con el más simple, debe establecerse correctamente. Pero aún tienes mucha sobrecarga aquí. Si, y por eso estos tres casos de prueba aquí se colocan en la misma suite de pruebas, si comparten, por ejemplo, una plantilla común con la que deberían funcionar, tendrían que repetir todos los pasos. Y tal vez una forma aún más eficiente sea agregar algo que yo llamaría una caché del sistema de archivos encima de eso. Entonces, la estrategia que haces aquí es la siguiente. Comienzas con tu suite de pruebas, y cuando comienza, creará lo que yo llamaría un directorio de plantilla. Por lo tanto, todos los pasos que cada una de tus pruebas requerirá ya se habrán realizado en el directorio de plantilla. Ahora, el truco es que cuando creas una nueva prueba, primero creará un directorio temporal pero hará una copia del directorio de plantilla. Ahora eso podría ser incluso tan eficiente como simplemente vincularlo, lo que significa que prácticamente no tienes sobrecarga. Cada archivo que aparezca en este directorio temporal uno será solo algunos enlaces, por lo que en realidad ni siquiera hay sobrecarga en el contador de tamaño de archivo. Pero, por supuesto, puede haber problemas aquí, por ejemplo, si tu utilidad escribe, Simulink podría no ser la elección correcta. Puedes mezclar, pero en nuestro caso, por ejemplo, estamos haciendo muchas modificaciones. Lo más simple fue simplemente una copia, y la copia recursiva aún fue mucho más rápida que seguir los pasos de la plantilla. Dicho esto, una vez que hay un directorio temporal, simplemente puedes hacer referencia a él y tus pruebas pueden ejecutarse.

4. Creación de directorios temporales y servicio de contenido

Short description:

Se crean directorios temporales para cada prueba, eliminando la necesidad de pasos de andamiaje. Este enfoque garantiza la reproducibilidad y acelera las pruebas posteriores. Para servir contenido, envuelve la funcionalidad en objetos de servicio y utiliza un asignador de puertos para asignar dinámicamente los puertos disponibles.

Y haces lo mismo, por ejemplo, con la prueba número dos, se crea el directorio y luego se hace referencia a él. Y lo mismo, por supuesto, con una tercera prueba. Antes de que se ejecute la prueba, se crea el directorio temporal, y ya obtendrá todo el contenido de la plantilla y no se requieren pasos de andamiaje. Simplemente ejecutas tus pruebas y todo está bien.

Otra ventaja aquí es, por supuesto, que es muy reproducible. Entonces, la primera ejecución, digamos, de la prueba uno puede llevar un poco más de tiempo, pero luego, dos, tres e incluso más pruebas, simplemente utilizarán el directorio de plantilla temporal, por lo que serán realmente rápidas, y lo veremos en una demostración en un minuto.

Ahora, ¿qué hay de la parte de servir contenido? Lo que puedes hacer aquí, en lugar de simplemente desencadenar, no sé, crear, por ejemplo, un servidor sobre la marcha, en realidad envolverás todas estas cosas en pequeños objetos que también podrías llamar servicios, ahora un servicio en tu código JavaScript, por ejemplo, y en lugar de simplemente iniciar un servidor, un servidor HTTP, por ejemplo, necesitarías pasar por un asignador de puertos de antemano. Ahora, el trabajo del asignador de puertos es asegurarse de que no solo selecciones un puerto fijo para él, digamos 8080, sino que obtengas un puerto libre.

5. Gestión de Puertos y Recursos

Short description:

Tener múltiples conjuntos de pruebas ejecutándose en paralelo puede causar conflictos si requieren el mismo servicio en un puerto fijo. Para asignar puertos dinámicamente, se utiliza un asignador de puertos que garantiza la disponibilidad y asigna un puerto para abrir un servidor HTTP. Las instancias resultantes son gestionadas por un administrador de recursos, que se encarga de limpiar automáticamente después de que finalice el caso de prueba, incluso en presencia de afirmaciones fallidas o problemas de código.

Porque al pensar en, ya sabes, tener múltiples conjuntos de pruebas ejecutándose en paralelo y ambos están ejecutando un caso de prueba que requiere el mismo servicio. Si fijaras ese puerto, digamos 8080, entonces tendrías un conflicto potencial aquí. E incluso si por alguna razón tienes alguna lógica en tu aplicación donde dices, oh, dependiendo del caso de prueba, simplemente incremento un contador. Bueno, eso también podría fallar, ¿verdad? Porque no sabes desde dónde estás ejecutando esta prueba desde un sistema CICD, por ejemplo, no sabes qué puertos están disponibles. Así que podría ser que 8080 ya esté ocupado allí, tal vez 8081 esté disponible u otro número. Por lo tanto, el asignador de puertos debe asegurarse de obtener dinámicamente un puerto que realmente esté disponible. Y lo devolverá. Y luego puedes abrir, por ejemplo, un servidor HTTP en el puerto correspondiente. Muy bien. Los colocas, las instancias resultantes, en un administrador de recursos, eso es muy útil para más adelante. Y luego, por supuesto, tu caso de prueba puede continuar, puede crear otro servicio. El mismo principio aquí. Se colocará en un administrador de recursos. Y ahora el administrador de recursos, cuando el caso de prueba finalice, será responsable de limpiar todo eso. Pero eso se da por hecho aquí. No se necesita ningún paso manual, lo cual puede ser muy útil, especialmente si, digamos, olvidas ocuparte de, por ejemplo, afirmaciones fallidas y cosas así. Así que incluso podrías tener un problema en el código de tu caso de prueba. E incluso en esos casos, quieres cerrar de manera confiable estos servicios, y el administrador de recursos simplemente lo hace. Por lo tanto, siempre es una buena estrategia tener estas limpiezas implícitas y manejadas correctamente de forma predeterminada.

6. Configuración y Ejecución de Pruebas

Short description:

En nuestra configuración, utilizamos Jest como ejecutor de pruebas, Playwright para la verificación del navegador y TypeScript para escribir las pruebas. Ejecutamos todo en Azure Pipelines para la verificación y monitoreo continuos. Las pruebas interactuaron con nuestro código escrito en TypeScript y utilizaron un complemento llamado GLTS Jest. Jest generó un archivo con formato JUnit para su inspección a través de Azure DevOps. Aquí tienes un ejemplo de una prueba que utiliza funciones especiales y un objeto de contexto.

Entonces, en nuestro caso, ¿cuál fue la configuración básica para ejecutar tales pruebas? En realidad, lo llamaría bastante sencillo. Estábamos utilizando Jest como ejecutor de pruebas. Eso siempre es una buena base porque proporciona mucha comodidad. También se pueden proporcionar argumentos de línea de comandos para, por ejemplo, seleccionar una prueba específica y ya tienes todo un ecosistema a tu disposición.

Lo siguiente que utilizamos fue Playwright, porque como se mencionó en un ejemplo, tuvimos que verificar la salida en un navegador, simplemente verificar, por ejemplo, que se sirva algún HTML no fue suficiente. Queríamos ver que la renderización funcionara, que donde está este HTML, por ejemplo, realmente mostrara algo de JavaScript y que esto estuviera haciendo las cosas correctas después de todo. Luego, lo que utilizamos para escribir la prueba fue TypeScript. Quería asegurarme, por supuesto, de que no haya errores o problemas en nuestras pruebas en sí. Eso haría que la depuración fuera aún más brutal que de cualquier manera, solucionar algunas pruebas fallidas. Y ejecutamos todo en Azure Pipelines para que se verifique y monitoree continuamente.

Ahora, poniéndolo todo en un diagrama, se ve así. Nuestro sistema CISD se activa todos los días a las cuatro de la mañana. Ejecuta las pruebas. Estas serán pruebas de métricas más adelante. Esto simplemente iniciaría un proceso de Node.js ejecutando Jest e interactuando con nuestras pruebas que se han escrito en TypeScript. Tenemos un complemento o un transformador llamado GLTS Jest. Ahora, estas pruebas pueden usar Playwright, pueden usar otros recursos, lo que sea que hagan. Toda la interacción es ahora desde estos casos de prueba. Y al final del día, Jest escribe un archivo con formato JUnit que luego se puede publicar desde el pipeline de CICD. Y eso permite una inspección completa desde el portal web de Azure DevOps, pero también, por supuesto, a través de una API. Así que es bastante conveniente, bastante bueno. Puedes tener informes automáticos. Si algo falla, recibes una notificación por correo electrónico o en tu canal favorito, por ejemplo, en Teams u otro sistema. Pero eso es bastante genial.

¿Cómo se ve entonces una prueba? Aquí tienes un ejemplo. Lo que hicimos fue repetir esa definición normal de conjunto de pruebas solo por conveniencia. Entonces simplemente inicias esto como lo harías normalmente en Jest. Pero lo que obtienes son funciones especiales, como ciclo de vida, como configuración, por ejemplo, pero también una función especial de testing. Ahora, la ventaja de ese enfoque es que en cada una de esas funciones, tenemos este repetidor en ejecución y luego podemos acceder a un contexto. De lo contrario, tenemos ciertos parámetros que se colocan en el código a través de variables de entorno, por lo que se pueden configurar fácilmente en cualquier máquina.

7. Pruebas de Versiones de Utilidades CLI y Contexto de Prueba

Short description:

En nuestros pipelines de CI/CD, probamos diferentes versiones de nuestra utilidad CLI. El contexto de prueba garantiza que los procesos se ejecuten en el contexto correcto, incluido el uso de los directorios correctos. El contexto de prueba establece el directorio de trabajo actual en un directorio temporal, gestionando eficientemente los recursos. El contexto de prueba no es un marco de trabajo disponible públicamente, pero el código fuente está accesible en el repositorio de GitHub. El contexto de prueba en TypeScript permite operaciones asíncronas y mapea automáticamente las rutas de archivo al directorio temporal. Cada conjunto de pruebas se enfoca en un subcomando específico, y una función de configuración se encarga de los pasos necesarios para preparar el directorio e instalar las dependencias para una prueba exitosa.

Están configurados, por supuesto, en nuestros pipelines de CI/CD. Y aquí puedes ver, por ejemplo, lo que hacemos para probar diferentes versiones de nuestra utilidad CLI por defecto, siempre usará la última versión pero en realidad puedes configurarlo para una versión diferente una versión previa, por ejemplo, que podría ser interesante O si quieres ver eso, quiero decir, si hay una regresión ocurriendo, esto ya funciona, puedes hacer un nuevo caso de prueba pero ejecutarlo también contra una versión anterior, por supuesto Y todo esto está cubierto, por supuesto, por esos parámetros.

De lo contrario, este contexto, por supuesto, garantiza que cualquier cosa que hagas, como ejecutar, por ejemplo, generar otro proceso de línea de comandos, siempre lo harás en el contexto correcto Por ejemplo, utilizando los directorios correctos Así que aquí, hay mucha magia implícita detrás de eso pero ten la seguridad, lo más importante que hace es establecer solo el directorio de trabajo actual en un directorio temporal ya establecido Y como puedes ver, esa es la ventaja de este envoltorio Ni siquiera ves la creación de nada de eso Simplemente sucede y sucede de manera confiable y todos estos recursos se gestionan en un mejor contexto Así que todo eso no es, digamos, un marco de trabajo disponible públicamente Todo el código fuente está disponible públicamente pero no es, digamos, una biblioteca que puedas tener está diseñado específicamente para nuestra solución pero puedes echar un vistazo al repositorio de GitHub para obtenerlo.

Correcto, ¿entonces de qué se trata este contexto de prueba? Esa es la definición de TypeScript. Lo más importante, todo es asíncrono. Incluso las cosas que no se llaman algo async son asíncronas. Por ejemplo, si ejecutas algo, esperas a la promesa y la promesa se resuelve cuando, por ejemplo, este proceso que iniciaste se ha completado Entonces, la cadena que obtienes es en realidad el flujo de salida Ahora, si usas, en este caso, run async, entonces obtienes de vuelta el proceso en ejecución y deberás esperar explícitamente, por ejemplo, y luego puedes interactuar con él de una manera mucho más agradable Y también tienes todo siempre se hace en relación a un directorio temporal Entonces, para el archivo, no necesitas saber dónde está el directorio temporal Simplemente proporcionas rutas de archivo relativas y se mapearán automáticamente al directorio temporal, lo cual es genial porque eso significa que realmente no es necesario que un desarrollador que realiza esta prueba tenga idea de dónde se colocarán los archivos Simplemente sucede automáticamente y puedes concentrarte en lo que debería estar ahora dentro de esta estructura.

Correcto, dicho esto, echemos un vistazo rápido a cómo se ve en la práctica Lo que veo aquí es un conjunto de pruebas que tenemos para probar un subcomando específico de nuestra utilidad de línea de comandos llamada Pilot Build Entonces, cada conjunto de pruebas que tenemos para un subcomando específico Y lo que puedes ver es que en el ejemplo tenemos una función de configuración aquí y se encarga de estos pasos de plantilla Entonces, en este caso, ejecuta bastantes pasos al principio Bueno, inicia nuestra CLI para preparar este directorio pero luego incluso instala algún bundler e incluso instala algún otro tipo de dependencias Entonces se ejecuta en nuestro caso aquí un par de veces y puede instalar Entonces hace eso, en realidad prepara todo como queremos que esté para ejecutar la prueba con éxito.

8. Ejecución de Pruebas y Configuraciones

Short description:

Al ejecutar pruebas, utilizamos una función de prueba para ejecutar el comando que queremos verificar. Realizamos afirmaciones en los archivos, centrándonos en puntos clave en lugar de utilizar instantáneas. Ejecutar una sola prueba lleva más tiempo, pero las pruebas posteriores aprovechan la estructura de carpetas y plantillas. La creación de la plantilla lleva tiempo debido a los procesos de instalación de NPM. Ejecutar pruebas localmente es solo una parte de la historia. La mayoría de las pruebas se ejecutan periódicamente, probando la utilidad CLI en múltiples configuraciones con diferentes versiones de Node.js y la utilidad de línea de comandos.

Y luego, más adelante, cuando realmente queremos ejecutar una prueba, simplemente usamos esta función de prueba y ejecutamos el comando que queremos verificar que funcione correctamente. En este caso, se llama 'pilot build'. Lo ejecutamos a través de MPX, solo para asegurarnos de cómo lo ejecutaría el usuario final. Y una vez hecho eso, podemos hacer afirmaciones en los archivos.

Por ejemplo, en este caso, solo nos interesa lo que está sucediendo en el archivo 'dist/index.js'. Algunos podrían argumentar que se podrían hacer cosas similares también con instantáneas. Y hemos experimentado mucho con instantáneas. Al final, descubrimos que las instantáneas no son buenas al menos para la utilidad que tenemos aquí, porque necesitaríamos muchas reglas de exclusión. E incluso sin estas reglas de exclusión, un archivo como 'index.js' depende en gran medida de todas las dependencias de módulos de Node que se han instalado. Y un ligero cambio en la versión de cualquiera de estas dependencias podría tener un impacto en el archivo. Por lo tanto, en su lugar, identificamos algunos puntos clave que definitivamente deben estar en este archivo. Y los tenemos aquí en las expectativas. Por supuesto, no hay una forma precisa de decir que esto sea completamente confiable. Siempre lo monitoreamos. Pero generalmente, si estos puntos están presentes, entonces esto funciona. Y de lo contrario, tenemos otras pruebas, por supuesto, que cubren más aspectos finales y aseguran que también en la pantalla suceda lo correcto.

Correcto, si ejecutamos esto, acabamos de hacer eso, estamos ejecutando solo una prueba, entonces la prueba única en este caso, por supuesto, se ejecuta un poco más lento, porque con una sola prueba, no obtienes la aceleración, ¿verdad? Solo obtienes ahora el tiempo para crear este directorio. Pero las otras pruebas, por supuesto, aprovecharían la estructura que puedes ver aquí en el lado izquierdo, donde ya has creado automáticamente esta carpeta, también has creado ahora una carpeta para el conjunto de pruebas, y allí hay una carpeta temporal ahora para esta plantilla que solo se crearía una vez, por supuesto. Y a partir de esta plantilla, solo obtienes una copia allí, y cada modificación se realiza aquí. Y la creación de esa plantilla y todo lo que llevó más tiempo, porque los procesos de instalación de NPM llevan más tiempo, ¿verdad? En general, los 40 segundos realmente están, sí, arruinando el resultado. Sin embargo, se omitieron todas las demás pruebas, y esta prueba se ejecutó correctamente. Por supuesto, también podrías decir que esta prueba no se ejecutaría si, por ejemplo, vas a una versión donde sabes que hay un problema, y luego verías que la prueba no pasa, en el mismo sentido.

Correcto. Y luego, por supuesto, ejecutar localmente puede ser solo una parte de la historia. La mayoría de nuestras pruebas se ejecutan, como se mencionó, periódicamente, todos los días a las 4 de la mañana. Lo que estamos haciendo aquí son pruebas de métricas, por lo que es más eficiente que ejecutarlo localmente, porque aquí solo lo ejecuto en una configuración. Pero en realidad, lo que quiero es, es una utilidad de CLI utilizada por muchos usuarios. Quiero ejecutarlo en múltiples configuraciones. Quiero ejecutarlo con diferentes versiones en nuestro caso de Node.js. Quiero ejecutarlo, tal vez, con diferentes versiones de nuestra utilidad de línea de comandos.

9. Ejecución de pruebas en diferentes configuraciones

Short description:

Ejecutar pruebas en diferentes sistemas operativos e identificar problemas de compatibilidad es crucial para las utilidades de CLI. La integración continua y la implementación continua (CICD) proporcionan beneficios como notificaciones de fallos y la capacidad de manejar dependencias dinámicas. Si bien se recomiendan dependencias fijas hasta cierto punto, es importante considerar escenarios del mundo real donde los usuarios pueden tener diferentes versiones de dependencias. Las pruebas de matriz en Azure DevOps y otras tuberías de CI/CD permiten ejecutar pruebas en paralelo en diferentes configuraciones, como diferentes sistemas operativos y versiones de Node.js. Esto proporciona una cobertura de prueba más completa y ayuda a identificar problemas específicos de ciertas configuraciones.

Y también quiero ejecutarlo en diferentes sistemas operativos, porque puede haber alguna parte en la CLI que funcione, no sé, en Windows, pero no funciona en Mac, y quiero identificar eso. Y eso, por supuesto, es algo que en un sistema local será, bueno, difícil de hacer, y ahí es donde brilla el CICD. ¿Correcto, también obtienes, por supuesto, otras mejoras allí? Obtienes las notificaciones cuando algo falla, así que tienes algo todos los días que puedes buscar si tienes un problema, y deberías, por supuesto, tener en cuenta las dependencias dinámicas para eso.

Lo que quiero decir con esto es, por supuesto, puedes, digamos, endurecer todo. Puedes hacer, por ejemplo, que todas tus plantillas que hagas se hagan con dependencias fijas en, por ejemplo, NPM, para que siempre dependas de, no sé, hemos visto listas de emojis que dicen que uno, dos, tres deberían ser la versión, y eso, por supuesto, es hasta cierto punto recomendable, pero hacer todas las dependencias de manera fija ciertamente no es recomendable, porque si todas las pruebas siempre están verdes, siempre se mantendrán verdes, pero tus usuarios reales, ellos no harán todas sus dependencias, por supuesto, fijas, así que generalmente dirán, oh, simplemente no me importa. Si, digamos, hubo un cambio de versión de parche aquí, quiero tomarlo porque, no sé, podría contener una solución rápida para una vulnerabilidad de seguridad, y así deberías seguir eso, porque tus usuarios finales también lo harán, ¿verdad? Y así, un cambio en, por ejemplo, tu utilidad podría, por supuesto, ser bueno para activar tus pruebas, pero en general, incluso si tu utilidad no cambió, aún deberías ejecutar las pruebas y luego simplemente actualizar las dependencias solo para emular lo que harían los usuarios reales. Así que siempre ten en cuenta el equilibrio entre tener todo confiable y reproducible en tus pruebas y tenerlo lo más cercano posible a la realidad. Y en algún punto intermedio es donde quieres estar, eso es lo que debes considerar.

Ahora, las pruebas de matriz en, por ejemplo, Azure DevOps funcionan así. En otras tuberías de CI/CD, por ejemplo, GitHub Actions, funciona de manera muy similar. También es un archivo YAML, pero, por supuesto, algunos nombres son diferentes. Lo que haces allí generalmente es definir una clave llamada estrategia, y allí puedes tener una matriz. Luego ingresas una lista de nombres buenos. Por ejemplo, asignas Linux node 12 para donde quieres ejecutar en Linux, que es la versión de nodo 12. Y luego dentro, en realidad puedes tener cualquier tipo de variable que desees. Entonces, estos nombres son inventados, nombre de imagen y versión de nodo. Lo que realmente haces es que luego usas estos nombres de variables cuando, por ejemplo, asignas una cierta imagen o cuando instalas una cierta versión de nodo, y luego puedes hacer referencia a las variables que asignaste. Y lo que Azure DevOps realmente hará es ejecutar todas estas cosas en paralelo, al menos hasta el nivel de paralelismo permitido por Azure DevOps. Entonces, si solo tienes uno porque estás en el nivel gratuito, entonces aún los ejecutarás secuencialmente, pero simplemente ejecutarás todos estos como puedes ver aquí en una ejecución. ¿Correcto? Entonces aquí puedes ver, ahora tenemos los trabajos de Linux ejecutando las diferentes versiones de nodo. Tenemos el trabajo de Windows, pero todos se ejecutan en paralelo. Windows tardó mucho más. Ahí puedes ver que Windows es simplemente, bueno, creo que tiene un rendimiento no tan bueno en la instalación de NPM, esa fue la razón aquí, pero eso se probará al mismo tiempo. ¿Correcto? Lo que puedes obtener son lotes agradables. Entonces, cada uno de tus, digamos, sub-pipeline de métricas también puede tener un lote dedicado. Entonces puedes tener un lote para todo el conjunto de cosas que ves aquí arriba, pero también puedes tener un lote para cada pipeline. Y eso te da, por ejemplo, un buen nivel de indicador que puedes, por ejemplo, usar en algún panel interno o en alguna página. Entonces, cuando obtienes un estado parcialmente exitoso o incluso rojo una vez, entonces es hora de investigar.

10. Resultados de las pruebas y repositorio

Short description:

En nuestro caso, obtuvimos un éxito parcial porque no es posible decir simplemente que una sub-tarea falló al ejecutar las pruebas. Sin embargo, tuvimos un final exitoso donde publicamos los resultados de las pruebas. Los pipelines de Azure evalúan esto como un éxito parcial. Como estamos utilizando Jest y tenemos JUnit como salida, es fácil investigar las fallas al mirar el directorio publicado. Echa un vistazo al repositorio llamado Pruebas de Integración de ParallelsUI. Conéctate conmigo en LinkedIn o Twitter. Que tengan un excelente día, a todos. Adiós.

En nuestro caso, obtuvimos un éxito parcial porque creo que no es posible, pero en ese momento cuando comenzamos, no era posible decir que alguna sub-tarea falló en este caso, al ejecutar las pruebas, pero luego tuvimos un final exitoso donde simplemente publicamos los resultados de las pruebas. Así que eso siempre será exitoso. Por lo tanto, los pipelines de Azure lo evaluaron como un éxito parcial. En nuestro caso, por lo tanto, el amarillo generalmente significa rojo. Y así necesitas investigar. Pero nuevamente, como estás utilizando Jest, tienes JUnit como salida. Eso es bastante fácil de hacer. Además, por supuesto, publicamos, como se mencionó, todos los archivos generados. Por lo tanto, incluso puedes mirar hacia atrás y decir, hey, ¿cómo fue eso? ¿Hubo alguna prueba que falló? Echemos un vistazo al directorio publicado y investiguemos eso. Dicho esto, echa un vistazo al repositorio. Se llama Pruebas de Integración de ParallelsUI. Y les deseo una excelente conferencia. Pónganse en contacto, conéctense conmigo en LinkedIn o Twitter, y compartamos ideas. Que tengan un excelente día, a todos. Adiós.

11. Resultados de la encuesta y interpretaciones

Short description:

Durante la encuesta, alguien respondió de manera humorística que CLI significa camello, león e iguana. Aunque las respuestas inicialmente no sumaban cien, finalmente se ajustaron. Es interesante ver las diferentes perspectivas e interpretaciones dependientes del contexto.

Entonces, al principio, antes de tu charla, le pediste a la audiencia que respondiera una pregunta de la encuesta y tenemos los resultados de la misma. ¿Qué opinas al respecto? Yo diría, sí, como se esperaba, ¿verdad? Quiero decir, genial. Me pareció gracioso que alguien respondiera que CLI significa camello, león e iguana. No. Quiero decir, ¿qué se puede hacer? Todo depende del contexto, así que tal vez sea una buena elección. No conozco el contexto de la respuesta. Sí, sí, sí. Lo que encuentro más interesante es que no suma cien, pero redondeando, ¿verdad? Oh, vale, alguien acaba de cambiarlo. Ahora suma cien. Sí.

12. Pruebas de utilidades CLI con Cypress y Playwright

Short description:

El ponente explica que no ha utilizado el comando cy.exec de Cypress para probar las utilidades CLI. Aclara que la parte de Playwright en su charla solo se utilizó para la automatización del navegador, no como un marco de automatización de pruebas. Menciona que Cypress podría ser una opción viable para las pruebas de extremo a extremo basadas en el navegador.

Tenemos algunas preguntas de la audiencia que me gustaría que respondas. La primera sería, que también me intriga. ¿Ya has utilizado el comando cy.exec de cypress para probar las utilidades CLI? Porque en tu charla mencionaste el uso de Playwright. Entonces, ¿ya has utilizado el comando cy.exec para eso? No, no lo he hecho. La parte de Playwright en mi charla solo se utilizó en una parte, ¿verdad? Todos los tests aún se ejecutaron desde Jest, pero aquí utilizamos Playwright no como un marco de automatización de pruebas, sino como un marco de automatización del navegador porque queríamos utilizar el navegador y obtener información de allí. Pero sí, cypress también podría ser una opción viable allí. Y utilizo cypress en muchos proyectos para pruebas de extremo a extremo basadas en el navegador. Así que también podría ser una gran opción. Tiene mucho sentido. Otra pregunta también de la audiencia es si tienes alguna opinión sobre las pruebas de APIs utilizando curl ya que se ejecuta en la línea de comandos. Buena pregunta. Bueno, usualmente, depende de dónde comiences, ¿verdad? Si partes de lo que ya teníamos en un proyecto basado en Node.js, y por supuesto quieres aprovechar el ecosistema de Node.js, entonces diría que no uses curl, sino que comiences directamente tu solicitud en Node.js. Y bueno, terminas con algo que puedes manipular. Y por supuesto, investiga desde ese marco. Pero por supuesto, si, digamos, partes desde un ángulo completamente diferente, entonces podría tener sentido. Pero por supuesto, lo que me falta es qué usarías, por ejemplo, para inspeccionar el resultado. ¿Usarías una herramienta como jq, por ejemplo? ¿Cómo haces las afirmaciones de que son confiables? Probablemente lo mezclarías con algo más, ¿verdad? Sí, y eso es, por supuesto, la base, no sé. Quiero decir, cualquier herramienta puede ser una buena herramienta si se usa en el contexto adecuado. Para nosotros, por supuesto, tenía sentido desde el contexto. Y aquí, usar curl, por ejemplo, no habría tenido sentido. Sin duda. Entonces, otra pregunta que tenemos aquí es, ¿puede la caché del sistema de archivos también ser una caché remota? ¿Sería posible eso? Sí, se podría aprovechar de esa manera. La idea básica es, si hicieras eso, si ya has ejecutado una cierta prueba, no sé, digamos, localmente tienes node.js14 y ya has ejecutado todas las pruebas usando node.js14, entonces cuando entregues tu código de prueba y se ejecute automáticamente como ICD, entonces, por ejemplo, node.js14 se encontraría en la caché, y obtendrías una mejora masiva de velocidad para esa parte, ¿verdad? Y así, si tienes, digamos, muchos desarrolladores que ya utilizan diferentes bases para ejecutar sus pruebas, obtendrías ese beneficio. Podrías hacer eso. Sí, no lo hicimos, pero se puede. Sí, sí, sí. Tiene mucho sentido. Otro que encuentro muy interesante aquí, ¿estas tareas se pueden ejecutar en paralelo? Creo que mencionaste eso en la charla, ¿verdad? Sí, ejecutamos los conjuntos de pruebas en paralelo, lo cual es para nosotros, el mayor factor de aceleración. Ejecutar las pruebas dentro de un conjunto de pruebas en paralelo sería un poco más complicado. Quiero decir, todas dependen de formar esta plantilla como se sugiere en la charla, pero también se podría hacer. Por lo general, no lo hacemos porque aún hay, quiero decir, aún necesitarías tener tus pruebas ya resueltas de tal manera que no colisionen entre sí porque a veces, quiero decir, los puertos, etc., están todos seguros, pero no se sabe. Entonces, si estás, y simplemente, bueno, dijimos lo más grande. Me pregunto qué tan difícil es porque en otros tipos de pruebas, pruebas unitarias, pruebas instrumentales, siempre nos preocupamos por hacer las pruebas lo más independientes posible para poder aprovechar la paralelización, ¿verdad? ¿Es demasiado difícil hacer eso cuando estamos haciendo pruebas como las de la CLI? Diría que no, puede ser muy, muy similar. Es solo que no lo hicimos, no tuvimos un enfoque específico en eso. Genial. Florian, gracias nuevamente por la excelente charla. Y si quieres seguir conversando con Florian, puedes hacer más preguntas y él podrá responder en Discord. Muchas gracias, Florian. Gracias. Que tengan una excelente tarde, todos.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

DevOps.js Conf 2024DevOps.js Conf 2024
25 min
Atomic Deployment for JS Hipsters
Deploying an app is all but an easy process. You will encounter a lot of glitches and pain points to solve to have it working properly. The worst is: that now that you can deploy your app in production, how can't you also deploy all branches in the project to get access to live previews? And be able to do a fast-revert on-demand?Fortunately, the classic DevOps toolkit has all you need to achieve it without compromising your mental health. By expertly mixing Git, Unix tools, and API calls, and orchestrating all of them with JavaScript, you'll master the secret of safe atomic deployments.No more need to rely on commercial services: become the perfect tool master and netlifize your app right at home!
TestJS Summit 2021TestJS Summit 2021
36 min
Effective Performance Testing to your Server with Autocannon
Top Content
Performance testing expertise that is developed for a long time. In order to measure your server performance you need a tool that can efficiently simulate a lot of abilities and give you good measurements according your analysing criteria.Autocannon NPM library gave me exactly that - that library is super easy to install and has a very simple API to work with. Within a really short amount of time you can start do performance testing to your application and get good measurements in development environment and in your performance labs, and generate complicated testing scenarios.In this talk I will introduce Autocannon, explain how to efficiently analyse your server performance with it, and show how it helped me to understand complicated performance issues in my Node.js servers. At the end of this lecture, developers will be able to have the ability to integrate a fast and easy tool in order to measure your server performance.
TestJS Summit 2022TestJS Summit 2022
21 min
Delightful Integration Tests With Testcontainers
Top Content
Dockerized services are an excellent tool for creating repeatable, isolated environments ideal for integration tests. In this session, we'll look at the Testcontainers libraries which provide flexible and intuitive API for programmatically controlling lifecycle of your service dependencies in Docker containers. Running databases, Kafka, Elasticsearch, and even cloud technologies, straight from your test code ensures environment config is always up-to-date and consistent during local development and in CI pipelines.You’ll learn everything necessary to start adding powerful integration tests to your codebase without the headache of managing external service dependencies manually!
TestJS Summit 2022TestJS Summit 2022
23 min
Playwright Can Do This?
Guaranteeing that your application doesn't break while constantly shipping new features is tough. Obviously, with a continually growing app or site, you can't test everything manually all the time!Test automation and monitoring are crucial to avoiding shipping broken apps and sites. But what functionality should you test? When should you run your tests? And aren't complex test suites super slow?In this session, we'll get our hands on Playwright, the end-to-end testing framework, and learn how to automate headless browsers to ensure that you confidently ship new features.
DevOps.js Conf 2022DevOps.js Conf 2022
22 min
The Lazy Developer Guide: How to Automate Code Updates?
How to update hundreds of projects all at once? With organizations rapidly growing, demand for the scalability of the teams grows which directly impacts projects structure and ownership. The usual dilemma is mono- vs. multi-repos, but ... What if I tell you that it does not matter much? Both approaches can punch you in the face at some point, so perhaps it is better to think bottom-up.
Today I will walk you through some of the biggest challenges that exist in both approaches and those are managing dependencies across a few hundred projects, global code updates and many other things. I will also show you examples of how we solved this inside Infobip through building our own internal libraries.

Workshops on related topic

TestJS Summit 2021TestJS Summit 2021
85 min
Automated accessibility testing with jest-axe and Lighthouse CI
Workshop
Do your automated tests include a11y checks? This workshop will cover how to get started with jest-axe to detect code-based accessibility violations, and Lighthouse CI to validate the accessibility of fully rendered pages. No amount of automated tests can replace manual accessibility testing, but these checks will make sure that your manual testers aren't doing more work than they need to.
TestJS Summit 2022TestJS Summit 2022
163 min
Automated Testing Using WebdriverIO
Workshop
In this workshop, I cover not only what WebdriverIO can do, but also how you'll be using it day-to-day. I've built the exercises around real-world scenarios that demonstrate how you would actually set things up. It's not just "what to do," but specifically "how to get there." We'll cover the fundamentals of Automated UI testing so you can write maintainable, useful tests for your website and/or web app.
TestJS Summit 2021TestJS Summit 2021
111 min
JS Security Testing Automation for Developers on Every Build
WorkshopFree
As a developer, you need to deliver fast, and you simply don't have the time to constantly think about security. Still, if something goes wrong it's your job to fix it, but security testing blocks your automation, creates bottlenecks and just delays releases...but it doesn't have to...

NeuraLegion's developer-first Dynamic Application Security Testing (DAST) scanner enables developers to detect, prioritise and remediate security issues EARLY, on every commit, with NO false positives/alerts, without slowing you down.

Join this workshop to learn different ways developers can access Nexploit & start scanning without leaving the terminal!

We will be going through the set up end-to-end, whilst setting up a pipeline, running security tests and looking at the results.

Table of contents:
- What developer-first DAST (Dynamic Application Security Testing) actually is and how it works
- See where and how a modern, accurate dev-first DAST fits in the CI/CD
- Integrate NeuraLegion's Nexploit scanner with GitHub Actions
- Understand how modern applications, APIs and authentication mechanisms can be tested
- Fork a repo, set up a pipeline, run security tests and look at the results
GraphQL Galaxy 2021GraphQL Galaxy 2021
82 min
Security Testing Automation for Developers on Every Build
WorkshopFree
As a developer, you need to deliver fast, and you simply don't have the time to constantly think about security. Still, if something goes wrong it's your job to fix it, but security testing blocks your automation, creates bottlenecks and just delays releases, especially with graphQL...but it doesn't have to...

NeuraLegion's developer-first Dynamic Application Security Testing (DAST) scanner enables developers to detect, prioritise and remediate security issues EARLY, on every commit, with NO false positives / alerts, without slowing you down.

Join this workshop to learn different ways developers can access NeuraLegion's DAST scanner & start scanning without leaving the terminal!

We will be going through the set up end-to-end, whilst setting up a pipeline for a vulnerable GraphQL target, running security tests and looking at the results.

Table of contents:
- What developer-first DAST (Dynamic Application Security Testing) actually is and how it works
- See where and how a modern, accurate dev-first DAST fits in the CI/CD
- Integrate NeuraLegion's scanner with GitHub Actions
- Understand how modern applications, GraphQL and other APIs and authentication mechanisms can be tested
- Fork a repo, set up a pipeline, run security tests and look at the results