Qué considerar al escribir pruebas E2E #frontend@twiliosendgrid

Publicado: 2020-09-19

En Twilio SendGrid, escribimos pruebas de extremo a extremo (E2E) hacia el final de un nuevo ciclo de desarrollo de funciones o páginas para garantizar que todas las partes estén conectadas y funcionen correctamente entre el frontend y el backend desde la perspectiva del usuario final.

Hemos experimentado con varios marcos y bibliotecas de prueba E2E, como nuestro propio marco Ruby Selenium interno personalizado, WebdriverIO y, principalmente, Cypress durante más de dos años, como se destaca en las partes uno y dos de la serie de publicaciones del blog que documentan nuestra migración en todos las soluciones. Independientemente del marco o la biblioteca que utilizamos, nos encontramos haciéndonos las mismas preguntas sobre qué características podemos automatizar y escribir pruebas E2E. Después de identificar qué características podemos probar, también notamos que aplicamos la misma estrategia general una y otra vez para escribir y configurar las pruebas.

Esta publicación de blog no requiere ningún conocimiento previo sobre cómo escribir pruebas E2E en una determinada biblioteca o marco, pero ayuda si ha visto aplicaciones web y se pregunta cómo automatizar mejor las cosas en el navegador para probar que las páginas funcionan correctamente. Nuestro objetivo es mostrarle cómo pensar en las pruebas E2E, para que pueda aplicar estas preguntas y la estrategia general para escribir pruebas en cualquier marco que elija.

Preguntas para hacer si puede automatizar una prueba E2E

Cuando se trata de escribir pruebas E2E, debemos asegurarnos de que los flujos en las páginas que estamos probando en nuestra aplicación cumplan con ciertos criterios. Analicemos algunas de las preguntas de alto nivel que nos hacemos para determinar si es posible automatizar una prueba E2E.

1. ¿Es posible restablecer los datos del usuario a un cierto estado antes de cada prueba a través de alguna forma confiable como la API? Si no hay forma de restablecer de manera confiable a un usuario al estado que desea, no se puede automatizar y se espera que se ejecute como parte de sus pruebas de bloqueo antes de la implementación. También es un antipatrón y, por lo general, no determinista devolver a un usuario a un estado determinado a través de la interfaz de usuario porque es lento y la automatización de pasos a través de la interfaz de usuario ya es lo suficientemente inestable. Es más confiable hacer llamadas a la API para restablecer el estado del usuario sin tener que abrir una página en el navegador. Otra alternativa, si tiene un servicio que existe, es crear nuevos usuarios antes de cada prueba con los datos adecuados. Siempre que restablezcamos un usuario persistente o creemos un usuario antes de cada prueba, podemos centrarnos en las partes que estamos probando en la página.

2. ¿Tenemos control sobre la función, la API o el sistema que pretendemos probar? Si se trata de un servicio de terceros en el que confía para la facturación o para cualquier otra característica, ¿hay alguna forma de burlarse de ellos o hacer que funcione de manera determinista con ciertos valores? Desea obtener el mayor control posible sobre la prueba para reducir la descamación. Puede crear usuarios de prueba dedicados con recursos o datos aislados por ejecución de prueba para que no se vea afectado por nada más.

3. ¿Es el servicio o característica en sí lo suficientemente consistente para funcionar dentro de un tiempo de espera razonable? A menudo, es posible que deba implementar el sondeo o esperar a que se procesen ciertos datos y lleguen a la base de datos (como actualizaciones asincrónicas más lentas y eventos de correo electrónico activados). Si esos servicios ocurren con frecuencia dentro de un período de tiempo razonable y confiable, puede establecer tiempos de espera de sondeo adecuados mientras espera que aparezcan elementos DOM específicos o que se actualicen los datos.

4. ¿Podemos seleccionar los elementos con los que necesitamos interactuar en una página? ¿Está tratando con iframes o elementos generados sobre los que no tiene control y no puede modificar? Para interactuar con los elementos en una página, puede agregar selectores más específicos como los atributos `data-hook` o `data-testid` en lugar de seleccionar ID o nombres de clase. Los identificadores y los nombres de clase son más propensos a cambiar, ya que comúnmente se asocian con estilos. Imagínese tratando de seleccionar nombres de clase con hash o ID de componentes con estilo o módulos CSS de otra manera. Para elementos generados por terceros o bibliotecas de componentes de código abierto como react-select, puede envolver esos elementos con un elemento principal con un atributo `data-hook` y seleccionar los elementos secundarios debajo. Para tratar con iframes, creamos comandos personalizados para extraer los elementos DOM que necesitamos afirmar y actuar, sobre los cuales proporcionaremos un ejemplo más adelante.

Hay más consideraciones a tener en cuenta, pero todo se reduce a una pregunta: ¿Podemos repetir esta prueba E2E de manera consistente y oportuna y lograr los mismos resultados?

Estrategia general para escribir pruebas E2E

1. Averiguar los casos de prueba de alto valor que podemos automatizar . Algunos ejemplos incluyen pruebas de ruta feliz que cubren la mayor parte de un flujo de características: realizar operaciones CRUD a través de la interfaz de usuario para obtener la información del perfil de un usuario, filtrar una tabla para buscar resultados coincidentes dados algunos datos, crear una publicación o configurar una clave API. Sin embargo, puede ser mejor cubrir otros casos extremos y el manejo de errores con pruebas unitarias y de integración. Ejecute las preguntas que mencionamos en la sección anterior para ayudar a acortar su lista de casos de prueba.

2. Piense en cómo repetir estas pruebas configurando o eliminando la API tanto como sea posible. Para los casos de prueba automatizables de alto valor, comience a anotar qué cosas debe configurar a través de la API. Algunos ejemplos son sembrar al usuario con los datos adecuados si el usuario no tiene suficientes datos filtrables para la paginación, si los datos del usuario vencen en una ventana móvil de 30 días, o si es posible que necesitemos eliminar algunos datos sobrantes de un proceso exitoso o incompleto. pruebas antes de que la prueba actual comience de nuevo. Las pruebas deben poder ejecutarse y configurarse en el mismo estado repetible, independientemente de cómo se haya realizado correctamente o no la última prueba.

Es importante pensar: ¿cómo puedo restablecer los datos de este usuario al punto de partida para poder probar solo la parte de la función que quiero?

Por ejemplo, si desea probar la capacidad de un usuario para agregar una publicación para que finalmente aparezca en la lista de publicaciones del usuario, primero se debe eliminar la publicación.

3. Camine en el lugar de su cliente y realice un seguimiento de los pasos de la interfaz de usuario necesarios para finalizar por completo un flujo de funciones. Registre los pasos para que un cliente complete un flujo completo o una acción. Realice un seguimiento de lo que el usuario debe o no debe ver o con lo que interactuar después de cada paso. Haremos verificaciones de cordura y afirmaciones en el camino para asegurarnos de que los usuarios encuentren las secuencias de eventos adecuadas para sus acciones. A continuación, traduciremos las comprobaciones de cordura en comandos y aserciones automatizados.

4. Mantenga los cambios y automatice los flujos agregando selectores específicos e implementando objetos de página (o cualquier otro tipo de contenedor). Revise los pasos que anotó sobre cómo maniobrar y pasar por un flujo de funciones. Agregue selectores más específicos, como atributos de "gancho de datos" a los elementos con los que el usuario interactuó, como botones, modales, entradas, filas de tablas, alertas y tarjetas. Si lo prefiere, puede crear objetos de página, contenedores o archivos auxiliares con referencias a esos elementos a través de los selectores que agregó. A continuación, puede implementar funciones reutilizables para interactuar con los elementos procesables de la página.

5. Traduzca los pasos de usuario que registró en pruebas de Cypress con los ayudantes que creó. En las pruebas, comúnmente iniciamos sesión en un usuario a través de la API y conservamos la cookie de sesión antes de que se ejecute cada caso de prueba para permanecer conectado. Luego configuramos o eliminamos los datos del usuario a través de la API para tener un punto de partida consistente. Con todo en su lugar, visitamos la página que probaremos directamente para nuestra función. Continuamos con la ejecución de pasos para el flujo, como un flujo de creación, actualización o eliminación, afirmando lo que debería suceder o ser visible en la página a lo largo del camino. Para acelerar las pruebas y reducir la descamación, evite restablecer o generar estado a través de la interfaz de usuario y omita cosas como iniciar sesión a través de la página de inicio de sesión o eliminar cosas a través de la interfaz de usuario para centrarse en las partes que desea probar. Asegúrate de hacer siempre esas partes en los ganchos `before` o `beforeEach`. De lo contrario, si usó ganchos `after` o `afterEach`, las pruebas pueden fallar en el medio, lo que hace que sus pasos de limpieza nunca se ejecuten y que las ejecuciones de prueba posteriores fallen.

6. Martille y selle la prueba de descamación. Después de implementar las pruebas y pasar un par de veces localmente, es tentador configurar una solicitud de extracción, fusionarla de inmediato y hacer que las pruebas se ejecuten según un cronograma con el resto de su conjunto de pruebas o activarlas en sus pasos de implementación. Antes de hacer eso:

    1. Primero, intente dejar al usuario en varios estados y vea si sus pruebas aún pasan para asegurarse de que tiene los pasos de configuración adecuados.
    2. A continuación, investigue la ejecución de sus pruebas en paralelo cuando se activen durante uno de sus flujos de implementación. Esto le permite ver si los mismos usuarios están pisoteando los recursos y si se están dando condiciones de carrera.
    3. Luego, observe cómo se ejecutan sus pruebas en modo autónomo en un contenedor de Docker para ver si necesita aumentar los tiempos de espera o ajustar los selectores.

El objetivo es ver cómo se comportan sus pruebas en ejecuciones de prueba repetidas en diferentes condiciones y hacerlas lo más estables y consistentes posible para que dediquemos menos tiempo a corregir las pruebas y nos concentremos más en detectar errores reales en nuestros entornos.

Aquí hay un ejemplo de diseño repetitivo de prueba de Cypress en el que creamos un comando de soporte global de inicio de sesión llamado `cy.login (nombre de usuario, contraseña).` Establecemos la cookie explícitamente y la conservamos antes de cada caso de prueba para que podamos permanecer conectados e ir directamente a las páginas que estamos probando. También llevamos a cabo alguna configuración o desmontaje a través de la API y omitimos la página de inicio de sesión cada vez que se muestra a continuación.

Pensamientos finales

Además de comparar qué solución E2E es la mejor para usar, también es importante adoptar la mentalidad adecuada para las pruebas E2E. Es crucial primero hacer preguntas sobre si la función que desea probar cumple o no con los requisitos para ser automatizada. Debería haber formas de restablecer el usuario o los datos a un cierto estado de manera confiable (como a través de la API) para que pueda concentrarse en lo que está tratando de validar.

Si no hay una forma confiable de restablecer su usuario o datos al punto de partida adecuado, debe buscar herramientas de creación y API para crear usuarios con ciertas configuraciones. También puede considerar simular las cosas que puede controlar para que las pruebas sean lo más estables y consistentes posible. De lo contrario, debe considerar el valor y las compensaciones con su equipo. ¿Es esta característica una que debería dejar para las pruebas unitarias o la prueba de regresión manual cuando se envían nuevos cambios de código?

Para aquellas características que puede automatizar en las pruebas E2E, a menudo es más valioso cubrir los principales flujos de ruta feliz de sus usuarios. Una vez más, haga que las cosas sean repetibles de manera oportuna y consistente y elimine la descamación mientras escribe pruebas E2E con cualquier marco o biblioteca que desee.

Para obtener más información sobre las pruebas específicas de Cypress E2E, consulte los siguientes recursos:

  • Descripción general de 1,000 pies de escritura de pruebas de ciprés
  • TypeScript Todas las cosas en sus pruebas de Cypress
  • Manejo de flujos de correo electrónico en Cypress Tests
  • Ideas para configurar, organizar y consolidar sus pruebas de Cypress
  • Integración de pruebas Cypress con Docker, Buildkite y CICD