Con este artículo, continuamos una serie de publicaciones sobre cómo automatizamos en uno de los grandes proyectos LANIT el autoprocesamiento de pruebas manuales (en lo sucesivo denominadas pruebas automáticas) de un gran sistema de información (en lo sucesivo, Sistemas) y lo que surgió de él.
La segunda parte de la publicación se centra principalmente en los líderes de los grupos de automatización de pruebas de interfaz de usuario de extremo a extremo y la automatización de pruebas líder. Aquí encontrarán recetas específicas para la organización arquitectónica del código y la implementación, lo que respalda el desarrollo paralelo en masa de grandes grupos de pruebas frente a la variabilidad constante de las especificaciones de prueba. Esta parte contiene la lista completa de funciones necesarias para las pruebas de IU con algunos detalles de implementación, así como una lista de sorpresas que puede encontrar.
Aquí encontrará la Parte 1. (¿Por qué necesitábamos automatización? Organización del proceso de desarrollo y gestión. Organización de uso)FuentePila de arquitectura y tecnología
Estructura general del sistema y su entorno: diseño de alto nivel
Las principales tecnologías y bibliotecas utilizadas en el proyecto:
- JavaSE8 & maven & JUnit - pila de desarrollo;
- Selenium : una biblioteca para automatizar las acciones de un navegador web;
- Selenide : un complemento para Selenium, que tiene una API elegante que simplifica enormemente la interacción con el navegador y los elementos de la página;
- Selenoid y GGR : implementación de Selenium Grid y un equilibrador de carga para ejecutar pruebas en un servidor CI + contenedores preconfigurados con navegadores;
- Yandex Allure : para informes en el servidor CI.
Un diagrama general de los componentes de las pruebas automáticas y la infraestructura selenoide se muestra en los diagramas a continuación, incluidos los comentarios explicativos:
Marco de AutopruebasAplicación para la automatización de la regresión de la interfaz de usuario.
Entregado en código fuente. Utiliza JUnit4
run.propertiesArchivo de configuración para ejecutar Autotests. Define el nombre condicional del soporte utilizado y el tipo de ejecución: local o mediante contenedores externos y otras variables.
Complemento AllureUn archivo ejecutable especial que se instala en un servidor Bamboo.
Crea un informe HTML de prueba accesible a través de un servidor Bamboo.
Informe de pruebaPruebe el informe HTML disponible a través del servidor Bamboo.
Se almacena en el servidor Bamboo en los resultados del plan en una pestaña separada.
De bambúProporciona el lanzamiento de pruebas de integración en modo automático y manual.
Almacena informes de prueba en formato Allure.
servidor ggrEquilibrador de servidores de servidores selenoides.
Proporciona el equilibrio de las solicitudes de las pruebas automáticas (RemoteWebDriver) a varias instancias de servidores de selenio.
DockerServidor Docker para ejecutar contenedores y navegadores del servidor selenoide.
Servidor selenoideServidor de prueba remota
Proporciona el lanzamiento de pruebas en contenedores acoplados especializados utilizando un navegador "sin cabeza".
Realiza pruebas en modo paralelo de acuerdo con el número especificado de subprocesos simultáneos.
Selenoid-uiInterfaz de usuario del servidor al servidor selenoide.
Permite el monitoreo sobre la marcha del progreso de la prueba a través de VNC.
Selenoide-webdriverUn contenedor especializado con un navegador sin cabeza para ejecutar pruebas remotas.
Proporcionado desde el repositorio selenoide.
GitlabAlmacena el código fuente de la aplicación Autotests.
Esquema de trabajo
El siguiente diagrama muestra el esquema general del servicio AutoTests en el nivel de diseño de alto nivel.
Instalación e Implementación
Las pruebas automáticas se basan en cuatro servidores, uno de los cuales es el servidor de ejecución, y los otros tres proporcionan el lanzamiento de navegadores sin cabeza en contenedores. El poder actual de las pruebas automáticas proporciona 60 transmisiones simultáneas y se puede ampliar si es necesario.
El diagrama de implementación actual se muestra en el siguiente diagrama. En general, si no necesita más de 20 navegadores simultáneos (subprocesos de prueba), entonces es muy posible poner todo en un servidor 12 Kernels + 24 RAM. Comenzamos con esta configuración, pero a medida que crecieron los requisitos para el poder de las pruebas automáticas, descubrimos empíricamente que la configuración más estable y rentable es un servidor "típico" 12 Kernel + 24 RAM.
En nuestra experiencia, para probar sistemas con una interfaz web en Angular, la configuración aceptable del contenedor con el navegador debe ser el piso del kernel + GB de memoria. Una configuración más pequeña ralentiza el navegador e incluso puede provocar bloqueos no identificables.
Estructura del código y organización
Antes de pasar a la estructura y organización del código, una vez más enumeraré las políticas y restricciones que finalmente determinaron la dirección del desarrollo de la arquitectura:
- Una gran cantidad de scripts de prueba complejos de extremo a extremo. Alta intensidad de desarrollo;
- alta volatilidad de los escenarios de prueba (su variabilidad);
- alta velocidad continua de entrega de escenarios (desarrollo y revisión);
- calificaciones iniciales de desarrolladores de autotests;
- Alto desarrollo planificado de desarrolladores.
Con base en lo anterior, los principales impulsores arquitectónicos son los siguientes:
- asegurando un código altamente estructurado para una fácil lectura y manejabilidad;
- separación y aislamiento máximos entre implementaciones de aplicaciones de pruebas específicas y clases transversales de funcionalidad común;
- reducción máxima de dependencias requeridas para facilitar el cambio;
- Reutilización razonable de código a nivel de clases transversales con posible duplicación de código aceptable a nivel de grupos de prueba independientes (subsistemas funcionales) para reducir dependencias y fusionar conflictos a nivel de desarrollo;
- rechazo de marcos complejos como spring, aspecto J para reducir el tiempo de "entrada" de desarrolladores novatos en el proyecto.
En general, este enfoque arquitectónico permitió implementar un desarrollo rápido e independiente en condiciones de alta variabilidad de escenarios con un proceso prácticamente continuo de entrega de nuevas pruebas a los productivos. La arquitectura y ahora resisten con éxito la "carga y el refinamiento" a pesar del hecho de que el sistema ya ha implementado más de 1,500 escenarios comerciales.
La estructura general del código y las descripciones de soluciones específicas clave se dan a continuación.
Estructura general del código y patrones de desarrollo.
La estructura general de la organización del código se basa en una arquitectura "en capas" (ver diagrama), que generalmente hereda el patrón de página recomendado por los desarrolladores de Selenium. Expandimos este patrón agregando un nivel de elementos web a la base y destacando el nivel del escenario de prueba:
- prueba de nivel de clase
- nivel de escenario de prueba
- nivel de página web
- nivel de elemento web
- marco de prueba (se muestra atenuando en el diagrama).
Cada nivel en este esquema tiene un conjunto específico de responsabilidades y funcionalidad. La intersección funcional entre capas o las dependencias ilegítimas entre ellas no estaban permitidas y eran la razón principal para la devolución del commit para revisión como parte de una revisión de código antes de la solicitud de fusión.
Además, se arregló una estructura "en capas" en la división del código en paquetes (ver diagrama a continuación).
Tal esquema hizo posible dividir todos los subsistemas (de los cuales había significativamente más que en el esquema) entre los desarrolladores y, como resultado, hizo posible el desarrollo independiente con un número prácticamente desaparecido de conflictos de fusión.
El siguiente diagrama muestra la estructura general de la implementación de la clase de prueba y el esquema de distribución para la implementación de los paquetes del proyecto.
Prueba de nivel de clase
El nivel de clase de prueba incluye una sola clase para una prueba individual en particular (la prueba se describe en el sistema de gestión de prueba como una secuencia lineal de scripts de prueba). La clase de prueba es una clase Junit con la anotación @ Test del método correspondiente. En general, una clase de prueba implementa solo un método de prueba.
Cada clase de prueba hereda de una clase base cuya tarea es inicializar todas las TestRules en RuleChain, es decir, inicializar una infraestructura de prueba como inicializar un controlador web, configurar directorios temporales y otros manejadores de utilidad de propósito general.
La clase de prueba es responsable de organizar la ejecución del escenario de prueba a través de:
- inicialización de datos comerciales de prueba (escena de prueba),
- llamada secuencial de scripts de prueba individuales (Acciones) de acuerdo con el escenario requerido con la transferencia de datos de prueba inicializados a ellos desde el paso 2.
Además, en el paso 2 debe haber una secuencia lineal sin ramificaciones ni puntos de decisión. La plantilla de implementación de clase se muestra a continuación.
Nivel de caso de prueba
El nivel de caso de prueba es responsable de la implementación de casos de prueba específicos como se describe. Un escenario de prueba en este contexto es una secuencia de operaciones realizadas por un usuario en un sistema a través de la interacción con elementos en las páginas web de la aplicación.
El objetivo principal de la clase de caso de prueba:
- ejecute la secuencia dada del script de prueba accediendo a los métodos de las clases inferiores de Página, usando
o transmitió datos de la escena de prueba,
o datos recibidos de páginas web (de clases de página); - Realice las pruebas comerciales requeridas para el éxito de la prueba en el contexto del modelo comercial y la escena de prueba. En otras palabras, la clase de caso de prueba NO verifica el marcado, la disponibilidad y la accesibilidad de los elementos, sino que opera en el modelo comercial de la escena de prueba, en realidad realiza pruebas comerciales.
La clase de caso de prueba está organizada como una "interfaz funcional":
- contiene solo un método público "aplicar" (@ Paso), que:
o proporciona la implementación del script como una llamada a una secuencia de "acciones" (métodos proporcionados por las clases de la página),
o acepta todos los objetos comerciales necesarios como entrada, mientras que NO CREA ningún objeto comercial en sí mismo y NO INTERACCIONA directamente con nada que no sean clases de página; - contiene X métodos privados (@ Step), cada uno de los cuales implementa un paso específico por separado del script de prueba (como se describe en TMS - Test Management System);
- No interactúa (no llama a métodos) con otras actividades, incluso actividades de un subsistema similar;
- no acepta entradas y no funciona con datos de inicio de sesión. En otras palabras, no sabe nada sobre los roles desde los que se inicia.
Esta organización de clase te permite:
- Proporcionar informe autodocumentado. Cada método corresponde a un punto específico en la especificación de prueba y está anotado por la anotación de encanto @ Paso;
- reutilice las clases de script de prueba en diferentes pruebas, ya que el script de prueba 1) no crea una escena de prueba y 2) no depende del inicio de sesión del usuario (la operación de inicio de sesión de inicio de sesión se realiza a nivel de clase de prueba) 3), la prueba no depende de otras clases secuencias de comandos
Nivel de página web
El nivel de página web es un patrón de página clásico para probar en Selenium. La clase de página contiene definiciones de elementos web específicos y un conjunto de métodos públicos para realizar ciertas acciones grupales en el contexto de los pasos del caso de prueba.
La clase de página es directamente responsable de ingresar datos comerciales en elementos de interfaz específicos, trabajar con el controlador web (iniciar JS, por ejemplo) y, en consecuencia, probar formatos, verificar el diseño y la estructura de la página web para verificaciones básicas como: el elemento no es encontrado / no disponible y el artículo no contiene el valor requerido.
La clase de página tampoco incluye y no puede acceder a otras páginas y sus métodos. Además, las clases de página no llevan a cabo verificaciones comerciales, limitándose solo a verificaciones estructurales a nivel de elementos web en el caso general, proporcionando "hasta" al nivel de "script de prueba" datos recibidos de las páginas.
Nivel de elemento web
La capa de elementos web incluye una biblioteca de elementos finitos que pueden estar en una página web. Incluye primitivas específicas y conglomerados más complejos, que consta de varios elementos que llamamos widgets. Ejemplos de widgets pueden ser construcciones como "pajinators", menús globales, varios marcos y ventanas modales, elementos complejos como YandexMap o el reproductor de Youtube. Los elementos web organizan la composición con clases de página específicas y tampoco saben nada sobre otros elementos.
En general, si el proyecto tiene algún tipo de identificación global única de todos los elementos de la interfaz con su ID, entonces tiene sentido organizar el nivel de elementos web como una biblioteca global con solicitud de elementos específicos por su ID a través de las clases de configuración de fábrica o \ xml en la biblioteca de Spring. Pero no en todos los proyectos esto es posible.
Marco de prueba
El concepto de desarrollar pruebas automáticas, como se muestra en el diagrama anterior, se basa en la idea de un marco en el que se proporciona un conjunto de funciones del sistema para todas las pruebas automáticas: están perfectamente integradas y permiten a los desarrolladores de pruebas automáticas centrarse en cuestiones específicas de implementación comercial de clases de prueba.
El marco incluye los siguientes bloques funcionales:
- Reglas: inicialización y finalización de componentes de infraestructura de prueba como inicialización de WebDriver y recepción de una prueba de video (descrita con más detalle a continuación);
- WebDriverHandlers: funciones de ayuda para trabajar con un controlador web, como ejecutar Java Script o acceder a los registros del navegador. Implementado como un conjunto de métodos estáticos sin estado;
- WebElements: una biblioteca de elementos web típicos o sus grupos, contiene la funcionalidad de función cruzada requerida y el comportamiento típico. En nuestro caso, esta funcionalidad incluye una posible verificación de la finalización de operaciones asincrónicas en el lado del navegador web. Implementado como extensiones de elementos web de las bibliotecas Selenium y Selenide.
Inicialización del entorno de prueba. Reglas
La clase clave para todas las clases de prueba es BaseTest, de la cual se heredan todas las clases de prueba. La clase BaseTest define el "corredor" de pruebas de Junit y el RuleChain utilizado, como se muestra a continuación. El acceso desde las clases de prueba de la aplicación a las funciones proporcionadas por las clases de reglas se lleva a cabo a través de los métodos estáticos de las clases de reglas utilizando el identificador de hilo "hilo" como clave.
Los detalles de la implementación de las clases base para el marco de prueba automática se mostrarán en la siguiente parte del artículo: consulte la Parte 2-1. Implementación de clase base para todas las pruebas y JUnit ChainRule.
Documentación de resultados a través de informes de Allure.
Para obtener informes detallados sobre las pruebas realizadas, se utiliza Allure Framework, integrado con Bamboo a través de
Allure Plugin . Esto brinda una oportunidad para que consumidores específicos de pruebas (equipo de pruebas funcionales) no solo reciban datos sobre el hecho de una falla de prueba específica, sino también para restaurar fácilmente y, si es necesario, repetir una prueba descartada en modo manual.
Para documentar el informe de prueba, se utiliza la siguiente funcionalidad:
- Anotaciones de Allure y Junit para marcar el informe por los pasos del guión de prueba, así como una descripción estática de los metadatos para la prueba;
- Atraiga los archivos adjuntos para adjuntar al informe información adicional como una prueba de video, captura de pantalla, resultados de diagnósticos adicionales de los motivos del bloqueo, registros del navegador web descargados al / del navegador de archivos.
Las siguientes anotaciones de Allure y Junit se utilizan para marcar el informe.
- A nivel de clase de prueba:
o @ Feature: el nombre del subsistema funcional al que pertenece la prueba;
o @ Story: el nombre de un caso de prueba específico;
o @ Propietario: el nombre del desarrollador que realizó los últimos cambios a la prueba;
o @ TmsLink: enlace a la descripción de la prueba en el "sistema de gestión de pruebas" utilizado. - En el nivel del método de prueba (@ Prueba) de la clase de prueba:
o @ DisplayName: nombre completo del script de prueba. Se diferencia de @ Story en que le permite compartir los mismos guiones, que difieren solo en la composición de la escena de prueba; - A nivel de métodos que corresponden a los pasos específicos del escenario de prueba:
o @ Step: el nombre significativo del paso de prueba que refleja la esencia comercial de lo que está sucediendo.
El nombramiento de los pasos de prueba a través de @ Step le permite crear un informe detallado que repite completamente todos los pasos y elementos descritos en el escenario de prueba. Esto permite a los usuarios de pruebas automáticas rastrear fácilmente el curso del escenario de prueba y ayuda a determinar el punto de incidencia.
En general, usar Allure Framework demostró ser muy útil y fácil, con la excepción de algunas características relacionadas con la gran cantidad de datos que se generan en nuestro caso para una gran cantidad de scripts de prueba complejos largos (descritos más adelante en la sección "Retrospectiva").
¿Qué podría haberse hecho de manera diferente de inmediato? Use Spring Framework
A pesar del hecho de que al implementar las pruebas automáticas, nos negamos intencionalmente a usar Spring Core, en general, considero que su uso está justificado y funciona. El prototipo implementado mostró que usar Spring Core funciona para las siguientes tareas (aunque, por supuesto, no lo probamos completamente):
- inicialización de la escena de prueba;
- inicialización de páginas web y elementos.
La única característica es la necesidad de utilizar el contexto de alcance "predeterminado" del nivel de prototipo.
Inicialización de la escena de prueba. En las pruebas automáticas, la escena de prueba se inicializa mediante el método clásico de crear instancias de clase directamente en la clase de prueba a través de una simple fábrica nueva o de objetos. Aquí es bastante razonable utilizar la inicialización ya sea a través de clases de configuración o mediante archivos xml o archivos externos. Las ventajas son las siguientes: 1) simplifica el código de revisión, ya que los cambios en la escena de prueba ya no se aplican a las clases clave, 2) le permite conectar diferentes escenas de prueba para diferentes soportes u otras condiciones. Ahora el punto 2 no se usa con nosotros.
Inicialización de páginas web y elementos. La inyección de clases de páginas web y elementos web funciona en virtud de la inicialización perezosa perezosa de elementos web de seleniuro.
Por lo tanto, es posible crear una biblioteca de elementos web y páginas de acuerdo con una determinada especificación global de la interfaz de usuario y recibir en los enlaces de código a estos elementos no por la ruta absoluta y la identificación, sino por la identificación del proyecto de acuerdo con la especificación.
Debo decir de inmediato que no probé esto con mucho cuidado, de hecho me limité a una implementación de prueba de las "páginas" del inicio de sesión y la página "información" del usuario sobre este principio.
Retrospectiva Sorpresas
Aquí describí las sorpresas inesperadas que surgieron durante el desarrollo del proyecto, además de algunas consideraciones sobre lo que podría haberse hecho mejor si "no".
Marcado de front-end amigable con selenio (angular)
Una de las sorpresas más serias que encontramos fue el diseño de página "flotante", lo que llevó al hecho de que después de actualizar las aplicaciones de Angular, las pruebas cayeron porque Selenium no pudo encontrar los elementos debido a su ID (id, clase o ng-model) o rutas (para XPath). Esto condujo a la inestabilidad de las pruebas y la ambigüedad de las razones de la caída.
Desafortunadamente, este problema resultó ser generalmente insoluble. Lo eludimos con medidas organizativas: 1) al comienzo de la prueba de un nuevo candidato para el lanzamiento, todos los desarrolladores de pruebas automáticas se centran en la eliminación y el refinamiento rápidos en términos de edición de los valores de los localizadores de elementos web; 2) al final, llegamos a usar XPath relativo, que, por desgracia, no mejora el rendimiento en absoluto.
– , - .
«download»
«» :
.
. , , . , .
. , «» . , , , , , - ( ) - .
, , , . .
, . «» , , , .
. , . (~ 1000 ) 6 .
Selenoid-ggr . junit 20 ( Selenoid-) 60 ( ), . «» , 60 .
, , , 3-4 , preQA-. . , , AWS c , Selenoid- , AWS Selenoid, in/out .
, , E2E . preQA.
«»
, 60 60 .
«Timeline» « » ( ). , .
Hubo dos razones. El "enchufe" inicial fue causado por la apelación masiva al servicio de autorización y cuenta personal. Todos los navegadores comienzan simultáneamente a iniciar sesión y sobrecargan el servicio en el banco de pruebas.Las "columnas" posteriores resultaron estar relacionadas con el hecho de que las clases de prueba están ubicadas en carpetas por subsistema y junit las ejecutó casi simultáneamente, cargando así un subsistema funcional específico del soporte e ir más allá del límite de rendimiento de la configuración del soporte.Resolvimos el primer problema envolviendo el método del script de inicio de sesión en el equilibrador, que limitó el número máximo de operaciones de inicio de sesión a una constante dada.@Step(": ") public void apply(User user) { try { LoadCounter.get();
El segundo problema se resolvió activando la opción de ejecución de prueba aleatoria, que tiene el complemento junit maven.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>….</version> <configuration> <!-- Defines the order the tests will be run in. Supported values are "alphabetical", "reversealphabetical", "random","hourly", "failedfirst", "balanced" and "filesystem". --> <runOrder>random</runOrder> …
Cabe señalar que estos problemas estaban relacionados con el hecho de que no tuvimos la oportunidad de aumentar el rendimiento del banco de pruebas debido a los recursos limitados, y también porque estos recursos estarían inactivos la mayor parte del tiempo.
En general, resultó que el sistema E2E incorporado de las autocomprobaciones de la interfaz de usuario web puede usarse para pruebas de carga sustitutas y para evaluar el rendimiento y la estabilidad del sistema probado en su conjunto.
Alta carga en el servidor Bamboo y su almacenamiento
Si tiene muchas pruebas con una gran cantidad de operaciones (por ejemplo, la cantidad de operaciones registradas a través del
Paso es de 200 a 2000 con una cantidad de pruebas de aproximadamente 1300), entonces el volumen del informe Allure se vuelve más que significativo. Si agrega aquí también varios archivos adjuntos, como capturas de pantalla y archivos cargados / cargados, el volumen ya llega a cientos de megabytes. Por ejemplo, ahora para una regresión nocturna de 900 pruebas, la cantidad de datos cargados solo en Bamboo Allure es de aproximadamente 600 MB.
Está claro que los ingenieros de DevOps no están entusiasmados con la intensidad del consumo de espacio en disco y expresan activamente su insatisfacción, especialmente en relación con la necesidad de almacenar datos durante al menos un año.
Vemos una salida a esta situación mediante el uso de un servidor externo para almacenar y procesar informes, por ejemplo, como Allure Enterprise. Este servidor ya está pagado, pero nos permite resolver este problema. Actualmente estamos trabajando para probar e integrar Allure Enterprise en nuestro proyecto.
Para continuar
En el próximo artículo, mis colegas continuarán la historia y describirán la fascinante historia de las pruebas de servicios web utilizando Smartbear SoapUI Pro. Las fuerzas de dos ingenieros de automatización lograron automatizar alrededor de 500 scripts de prueba; para este propósito, tuve que implementar un marco adicional que expande significativamente la funcionalidad de las funciones estándar de la interfaz de usuario SOAP, pero más sobre eso más adelante.
Este artículo fue escrito en colaboración con el gerente del proyecto y el propietario del producto kotalesssk .Parte 1. Organizacional y gerencial. ¿Por qué necesitamos automatización? Organización del proceso de desarrollo y gestión. Organización de usoParte 2. Técnica. Arquitectura y pila técnica. Detalles de implementación y sorpresas técnicas.
Parte 2-1. Implementación de clase base para todas las pruebas y JUnit ChainRule
Parte 2-2. Implementación del proceso de carga de un archivo desde un contenedor con un navegador a un marco de prueba. Busque el nombre del archivo descargado por el navegador
Tenemos vacantes, ven a nosotros!