Un buen probador con habilidades de pensamiento crítico no puede ser completamente reemplazado por la automatización. Hacer que funcione de manera más eficiente es fácil. Con esta convicción, fui a nuestro departamento de pruebas con una nueva tarea, donde nosotros, junto con Pavel, iniciamos su implementación. Veamos que salió de eso.Junto con nuestros socios, estamos desarrollando, probando y respaldando activamente una familia de aplicaciones para diferentes plataformas: Android, iOS, Windows. Las aplicaciones se están desarrollando activamente, junto con lo cual aumenta el volumen de pruebas, principalmente la regresión.
Decidimos intentar facilitar y acelerar las pruebas automatizando la mayoría de los escenarios de prueba. Al mismo tiempo, no queríamos abandonar por completo el proceso de prueba manual, sino modificarlo.
La implementación de este enfoque comenzó con una de las aplicaciones de Android, de la que hablaré. El artículo será de interés para los autores principiantes de pruebas de IU, principalmente para aplicaciones móviles, así como para aquellos que quieran automatizar el proceso de prueba manual hasta cierto punto.
Vamos!
Punto de partida
Para cada plataforma, tenemos varias similares que realizan el mismo proceso comercial principal de las aplicaciones. Sin embargo, difieren entre sí en un conjunto de pequeñas funcionalidades auxiliares, se realizan bajo diferentes marcas según el cliente (debido a que la interfaz cambia de una aplicación a otra), y el proceso de negocio se puede personalizar agregando pasos adicionales.
Nos enfrentamos a ciertos problemas que deben abordarse. Dificultades similares pueden surgir en una situación diferente a la nuestra. Por ejemplo, si tiene una aplicación voluminosa con lógica empresarial difícil, llena de muchas pruebas.
Problema # 1: muchas pruebas de regresión
Los conjuntos de escenarios de prueba para cada aplicación son simultáneamente similares y diferentes entre sí, lo que contribuye a un aumento en la regresión y lo hace aún más aburrido. Sin embargo, debe probar todas las aplicaciones individualmente.
Teniendo en cuenta que las aplicaciones que ya se están ejecutando se actualizan regularmente, y en el futuro solo habrá más, el número total de pruebas crecerá inexorablemente.
Problema número 2: necesita probar en todas las versiones del sistema operativo móvil
Un requisito importante es la disponibilidad de nuestras aplicaciones móviles en una amplia gama de versiones de sistemas operativos. Por ejemplo, en el caso de Android en el momento de la escritura, estos son niveles de API del 17 al 28.
Idealmente, deberíamos probar en cada versión de Android, lo que complica aún más nuestra regresión. El proceso de prueba directa de la aplicación adquiere una rutina adicional multiplicada por el número de dispositivos: instalar y ejecutar la aplicación, devolviéndola a su estado original después de cada prueba individual. Al mismo tiempo, mantener su propia granja de dispositivos requiere bastante trabajo.
Solución: integre la automatización en el proceso de prueba manual
Una tarea típica de la automatización de pruebas es automatizar las pruebas de regresión. Por lo tanto, queremos mejorar la eficiencia del proceso de prueba hoy y evitar las posibles consecuencias del crecimiento de mañana.
Al mismo tiempo, somos conscientes de que es imposible e innecesario erradicar completamente las pruebas manuales mediante automatización. El pensamiento crítico y el ojo humano son difíciles de reemplazar por algo. Hay un buen artículo sobre este tema en el blog de Michael Bolton, The
End of Manual Testing (o
traducción de Anna Rodionova).
Pensamos que sería útil contar con un conjunto de pruebas automatizadas que cubrieran las partes estables de la aplicación y, en el futuro, escribir pruebas de errores encontrados y nuevas funcionalidades. Al mismo tiempo, queremos asociar las pruebas automáticas con los conjuntos de pruebas existentes en nuestro sistema de administración de pruebas (usamos TestRail), y también permitir que los evaluadores ejecuten fácilmente pruebas automáticas en dispositivos físicos en la nube (elegimos Firebase Test Lab como la infraestructura de la nube).
Para comenzar y probar, tomamos una de nuestras aplicaciones de Android. Era importante tener en cuenta que si la solución era exitosa, sus mejores prácticas podrían aplicarse a nuestras otras aplicaciones, incluso en otras plataformas.
Lo que queremos obtener como resultado:
- Automatización de pruebas de regresión.
- Integración con el sistema de gestión de pruebas.
- Posibilidad de inicio manual parametrizado de pruebas automáticas en dispositivos en la nube.
- La posibilidad de reutilizar la solución en el futuro.
A continuación, hablaré por separado sobre la implementación de cada uno de estos puntos con una pequeña inmersión en el componente técnico.
Esquema general de implementación de soluciones
Pero primero, un resumen general de lo que obtuvimos:

Las pruebas automáticas se ejecutan de dos maneras:
- Desde CI después de la fusión o solicitud de extracción al maestro.
- Probar manualmente desde la interfaz web de Jenkins Job.
En el caso de un lanzamiento manual, el probador debe indicar el número de la compilación correspondiente o descargar 2 APK de la computadora: con la aplicación y con las pruebas. Este método es necesario para que pueda ejecutar las pruebas necesarias en cualquier momento en cualquier dispositivo disponible.
Durante las pruebas, sus resultados se envían a TestRail. Esto sucede de la misma manera que si el probador realizara la prueba manualmente e ingresara los resultados de una manera familiar para él.
Por lo tanto, dejamos el proceso establecido de pruebas manuales, pero le agregamos automatización, que realiza un conjunto específico de pruebas. El probador "recoge" lo que se hizo automáticamente y:
- ve el resultado de los casos de prueba en cada dispositivo seleccionado;
- puede verificar cualquier caso de prueba manualmente;
- realiza casos de prueba que aún no están automatizados o que no pueden optimizarse por ningún motivo;
- toma la decisión final sobre la prueba actual.
Ahora pasemos a la descripción prometida de la implementación.
1. Pruebas automáticas
Las herramientas
Utilizamos 3 herramientas para interactuar con la interfaz de usuario:
- Expreso
- Barista
- UI Automator.
La herramienta principal y con la que comenzamos es Espresso. El argumento principal a favor de su elección fue el hecho de que Espresso le permite probar usando el método de caja blanca, proporcionando acceso a la Instrumentación de Android. El código de prueba está en el mismo proyecto que el código de la aplicación.
Se necesita acceso al código de la aplicación de Android para llamar a sus métodos en las pruebas. Podemos preparar nuestra aplicación para una prueba específica por adelantado ejecutándola en el estado correcto. De lo contrario, necesitamos alcanzar este estado a través de la interfaz, que priva a las pruebas de atomicidad, haciéndolas dependientes unas de otras, y simplemente consume mucho tiempo.
Durante la implementación, se agregó otra herramienta a Espresso: UI Automator. Ambos marcos son parte de
la Biblioteca de soporte de pruebas de Android de
Google . Usando el UI Automator, podemos interactuar con varios cuadros de diálogo del sistema o, por ejemplo, el Cajón de notificaciones.
Y el último en nuestro arsenal fue el marco de Barista. Es un envoltorio alrededor de Espresso, que le ahorra el código repetitivo al implementar acciones comunes del usuario.
Teniendo en cuenta el deseo de poder reutilizar la solución en otras aplicaciones, es importante tener en cuenta que las herramientas enumeradas están destinadas exclusivamente a aplicaciones de Android. Si no necesita acceder al código de la aplicación bajo prueba, entonces probablemente preferirá usar un marco diferente. Por ejemplo, el muy popular Appium hoy. Aunque también puede intentar acceder al código de la aplicación con la ayuda de puertas traseras, que es un buen
artículo en el blog de Badoo. La elección es tuya.
Implementación
Como patrón de diseño, elegimos Testing Robots, propuesto por Jake Wharton en el
informe homónimo. La idea de este enfoque es similar al patrón de diseño de objetos de página común utilizado en las pruebas de sistemas web. El lenguaje de programación es Java.
Para cada fragmento independiente de la aplicación, se crea una clase especial de robot en la que se implementa la lógica empresarial. La interacción con cada elemento del fragmento se describe en un método separado. Además, todas las afirmaciones realizadas en este fragmento también se describen aquí.
Considere un ejemplo simple. El fragmento descrito contiene varios campos para ingresar datos y un botón de acción:

El código de la prueba de funcionalidad de inicio de sesión en sí:

Aquí verificamos el escenario positivo cuando los datos de autenticación ingresados son correctos. Los datos en sí se envían a las pruebas de entrada o se utilizan los valores predeterminados. Por lo tanto, el probador tiene la capacidad de parametrizar en términos de datos de prueba.
En primer lugar, esta estructura proporciona a las pruebas una excelente legibilidad cuando todo el script se divide en los pasos principales de ejecución. También nos gustó mucho la idea de transferir aserciones a los métodos individuales del robot correspondiente. Assert se convierte en el mismo paso, sin romper la cadena general, y sus pruebas aún no saben nada sobre la aplicación.
En el informe antes mencionado, Jake Wharton ofrece una implementación en Kotlin, donde es finito. Ya lo probamos en otro proyecto y realmente nos gustó.
2. Integración con el sistema de gestión de pruebas.
Antes de la introducción de la automatización, realizamos todas nuestras pruebas en el sistema de gestión de pruebas TestRail. La buena noticia es que hay una
API TestRail bastante buena, con la que pudimos conectar casos de prueba ya establecidos en el sistema con autotest.
Durante la ejecución de la prueba usando JUnit
RunListener , se capturan varios eventos, como
testRunStarted
,
testFailure
,
testFinished
, en el que enviamos los resultados a TestRail. Si usa AndroidJUnitRunner, entonces necesita informar sobre su RunListener de cierta manera, como se describe en la
documentación oficial
.También necesita comunicarse con varias entidades TestRail por su ID. Entonces, para conectar la prueba con el caso de prueba correspondiente, creamos una anotación simple
@CaseId
,
@CaseId
uso se muestra en el ejemplo de implementación de prueba anterior.
Código para implementar la anotación en sí:

Solo queda obtener su valor en el lugar correcto de Descripción:

3. Inicio manual de pruebas automáticas en dispositivos en la nube
Parametrización de inicio en el trabajo de Jenkins
Para organizar el inicio manual de las pruebas automáticas, utilizamos el
trabajo Jenkins de estilo libre . Se eligió esta opción porque la compañía ya tenía cierta experiencia con trabajos similares con Jenkins Job en otras áreas, en particular con los ingenieros de DevOps, a quienes compartieron con gusto.
Jenkins Job ejecuta un script basado en los datos transferidos desde la interfaz web. Por lo tanto, se implementa la parametrización de las ejecuciones de prueba. En nuestro caso, el script Bash inicia el lanzamiento de pruebas en los dispositivos en la nube Firebase.
La parametrización incluye:
- Seleccionando el APK deseado especificando el número de la compilación correspondiente o descargándolos manualmente.
- Ingrese todo tipo de datos de prueba.
- Ingresando datos personalizados adicionales para TestRail.
- Seleccione los dispositivos físicos basados en la nube en los que se ejecutarán las pruebas de la lista disponible en Firebase Test Lab.
- La selección de kits de prueba a realizar.
Veamos una parte de la página web de nuestro trabajo de Jenkins usando un ejemplo de una interfaz de selección de dispositivos y suites de prueba:

Cada elemento donde puede ingresar o seleccionar cualquier información se implementa mediante complementos especiales de Jenkins. Por ejemplo, la interfaz de selección de dispositivos se realiza utilizando el
complemento Active Choices . Usando un script maravilloso de Firebase, se obtiene una lista de dispositivos disponibles, que luego se muestra en la forma deseada en la página web.
Después de ingresar todos los datos necesarios, se inicia el script correspondiente, cuyo progreso podemos observar en la sección Salida de la consola:

Desde aquí, el probador que inició la ejecución de la prueba puede ir a TestRail o a la consola de Firebase utilizando las URL recibidas, que contiene mucha información útil sobre la ejecución de pruebas en cada uno de los dispositivos seleccionados.
Matriz de prueba final en Firebase Test Lab
La matriz de dispositivos en Firebase contiene la distribución de pruebas por los dispositivos en los que se ejecutaron:

Para cada dispositivo, puede ver el registro completo, el video de la ejecución de la prueba y varios indicadores de rendimiento. Además, puede acceder a todos los archivos que podrían haberse creado durante la ejecución de las pruebas. Usamos esto para descargar indicadores de cobertura de prueba del dispositivo.
Elegimos Firebase, ya que ya hemos utilizado este servicio para resolver otros problemas, y estamos satisfechos con la política de precios. Si cumple con 30 minutos de tiempo puro para las pruebas por día, entonces no necesita pagar en absoluto. Esta puede ser una razón adicional por la cual es importante poder ejecutar solo ciertas pruebas.
Es posible que prefiera una infraestructura de nube diferente que también se adapte bien a su proceso de prueba.
4. Reutilizar
¿Cómo se puede usar todo esto en el futuro? Desde el punto de vista de la base del código, esta solución es aplicable solo para aplicaciones de Android. Por ejemplo, durante la implementación, hemos agregado clases auxiliares
EspressoExtensions
y
UiAutomatorExtensions
, donde encapsulamos varias opciones para interactuar con la interfaz y esperamos a que los elementos estén listos. Esto también incluye la clase RunListener, que es responsable de la integración con TestRail. Ya los hemos colocado en módulos separados y los usamos para automatizar otras aplicaciones.
Si hablamos de otras plataformas, la experiencia adquirida puede ser muy útil para construir e implementar procesos similares. Estamos haciendo esto activamente en el área de iOS y estamos pensando en Windows.
Conclusión
Hay muchas opciones para implementar y usar la automatización de pruebas. Somos de la opinión de que la automatización es principalmente una herramienta diseñada para facilitar el proceso tradicional de pruebas "humanas" y no para erradicarlo.