Introducción a las pruebas de iOS con UI Automation

Abr 17, 2021
admin

Imagina poder escribir scripts que interactúen automáticamente con tu aplicación iOS y poder verificar los resultados. Con UI Automation puedes hacerlo. UI Automation es una herramienta proporcionada por Apple para realizar un nivel superior de pruebas en su aplicación iOS más allá de lo que se puede lograr con XCTest.

1. Caja blanca frente a caja negra

Es posible que haya oído la comparación de las pruebas de caja blanca frente a las pruebas de caja negra con respecto a cómo se puede probar una pieza de software. Si no estás familiarizado con estos conceptos, déjame explicarte cómo funcionan.

Pruebas de caja blanca

Imagina que hay una pieza de software que se ejecuta dentro de una caja. Con las pruebas de caja blanca, usted puede ver dentro de la caja y mirar todas las piezas de arena de cómo funciona el software, y luego tomar decisiones educadas sobre cómo probar el software. También puede tener ganchos de nivel más profundo en el software de las pruebas que usted escribe.

Las pruebas unitarias son pruebas de caja blanca. Cuando se escriben pruebas unitarias, el probador tiene acceso de grano fino al código bajo prueba. El probador puede realmente escribir pruebas que aprovechan el software bajo prueba en el método, o la unidad, nivel.

En el desarrollo de software iOS utilizamos el marco XCTest para realizar este tipo de pruebas. Echa un vistazo a otro tutorial que escribí sobre cómo empezar con XCTest.

Pruebas de caja negra

En las pruebas de caja negra, la caja es opaca. El probador no puede ver dentro de la caja. El probador no puede acceder y no conoce la implementación de la base de código para escribir pruebas. En su lugar, el probador se ve obligado a utilizar la aplicación como lo haría un usuario final interactuando con la aplicación y esperando su respuesta, verificando los resultados.

Hay al menos dos formas de ejecutar este tipo de pruebas.

  • Un probador que realiza repetida y manualmente una serie de pasos predefinidos y verifica visualmente los resultados.
  • Utilizar herramientas especializadas para probar la aplicación con APIs que se comportan de forma similar a como interactúa un humano.

En el desarrollo de aplicaciones iOS, Apple proporciona una herramienta llamada UI Automation para realizar pruebas de caja negra.

2. ¿Qué es la automatización de la interfaz de usuario?

UI Automation es una herramienta que Apple proporciona y mantiene para realizar pruebas automatizadas de alto nivel de las aplicaciones iOS. Las pruebas se escriben en JavaScript, adhiriéndose a una API definida por Apple.

La escritura de pruebas puede ser más fácil si se basa en las etiquetas de accesibilidad para los elementos de la interfaz de usuario en su aplicación. Pero no te preocupes, si no las tienes definidas, hay alternativas disponibles.

La API de automatización de la interfaz de usuario carece del típico formato basado en xUnit para escribir pruebas. Una diferencia con las pruebas unitarias es que el probador necesita registrar manualmente los éxitos y los fracasos. Las pruebas de Automatización de la UI se ejecutan desde el instrumento de Automatización dentro de la herramienta Instrumentos que viene con las herramientas para desarrolladores de Apple. Las pruebas se pueden ejecutar en el simulador de iOS o en un dispositivo físico.

3. Escribir pruebas de automatización de la interfaz de usuario

Paso 1: Abrir el proyecto de ejemplo

He actualizado el proyecto de ejemplo utilizado en el tutorial anterior sobre pruebas de iOS con algunos elementos adicionales de la interfaz de usuario que proporcionan algunos ganchos útiles para añadir pruebas de automatización de la interfaz de usuario. Descargue el proyecto desde GitHub. Abra el proyecto y ejecute la aplicación para asegurarse de que todo funciona como se espera. Deberías ver una interfaz de usuario similar a la que se muestra a continuación.

Antes de escribir cualquier prueba, no dudes en probar la aplicación de ejemplo para familiarizarte con su funcionalidad. Como usuario, puede introducir texto en el campo de texto y tocar el botón para ver una etiqueta en la pantalla que muestra la cadena invertida, introducida.

Paso 2: Crear una prueba de automatización de la interfaz de usuario

Ahora que está familiarizado con la aplicación de muestra, es el momento de añadir una prueba de automatización de la interfaz de usuario. UI Automation es una herramienta que se puede encontrar en Instruments. Para ejecutar la aplicación de ejemplo en Instrumentos, seleccione Producto > Perfil en el menú de Xcode. Seleccione Automation en la lista de herramientas.

Se abrirá la ventana principal de Instrumentos con un único instrumento listo para ser ejecutado, el instrumento de Automatización (el instrumento de Automatización ejecuta casos de prueba de Automatización de IU). También verá un área en la mitad inferior de la ventana que parece un editor de texto. Este es el editor de scripts. Aquí es donde escribirá sus pruebas de automatización de la interfaz de usuario. Para esta primera prueba, siga las siguientes instrucciones, añadiendo cada línea al script en el editor de scripts.

Comience almacenando una referencia al campo de texto en una variable.

var inputField = target.frontMostApp().mainWindow().textFields();

Establezca el valor del campo de texto.

inputField.setValue("hi");

Verifique que el valor se ha establecido correctamente y, si es así, pase la prueba. Fallar la prueba si no lo fue.

Aunque esta prueba es bastante trivial, tiene valor. Acabamos de escribir una prueba que comprueba la presencia de un campo de texto cuando se lanza la aplicación y que comprueba si se puede establecer una cadena aleatoria como valor del campo de texto. Si no me crees, elimina el campo de texto del storyboard y ejecuta la prueba. Verás que falla.

Esta prueba demuestra tres piezas importantes de la escritura de pruebas de automatización de la interfaz de usuario. En primer lugar, muestra cómo acceder a un elemento simple de la interfaz de usuario, el campo de texto. En concreto, accedemos a un diccionario de todos los campos de texto de la vista base de la aplicación a través de target.frontMostApp().mainWindow().textFields() y luego encontramos el campo de texto que nos interesa buscando el que tiene la clave Input Field. Esta clave es en realidad la etiqueta de accesibilidad del campo de texto. En este caso, está definida en el storyboard. También podemos definir la etiqueta de accesibilidad en código utilizando la propiedad accessibilityLabel en NSObject.

Acceder a la ventana principal de la aplicación, a la aplicación más frontal y al objetivo es habitual cuando se trabaja con UI Automation. Te mostraré cómo hacer esto más fácil y menos verboso más adelante en este tutorial.

En segundo lugar, esto muestra que se puede interactuar con los elementos de la interfaz de usuario en la pantalla. En este caso, establecemos el valor del campo de texto, imitando al usuario que interactúa con la aplicación introduciendo texto en el campo de texto.

Y en tercer lugar, el ejemplo también muestra una técnica para verificar lo que ocurre en la aplicación. Si el valor se establece con éxito, la prueba pasa. Si el valor no se establece, la prueba falla.

Paso 3: Guardar pruebas

Aunque escribir pruebas en el editor de scripts es conveniente, rápidamente se vuelve engorroso y difícil de mantener. Si sale de Instruments, cualquier cambio no guardado se descarta. Es necesario guardar las pruebas que escribimos. Simplemente copie y pegue su prueba en un nuevo documento en su editor de texto favorito y guárdelo. Puede encontrar las pruebas creadas en este tutorial en el proyecto de ejemplo en Jumblify/JumblifyTests/AutomationTests.js.

Para ejecutar la prueba, seleccione la pestaña central en el panel de la derecha, junto al editor de secuencias de comandos, y seleccione Añadir > Importar.

Se le pedirá que seleccione la secuencia de comandos a importar. Navegue hasta el script guardado e impórtelo. Puede seguir modificando el script en el editor de scripts. Cualquier cambio se guardará automáticamente en el archivo externo que ha creado.

Paso 4: Tocar un botón

Actualicemos nuestra prueba para probar la interacción con el botón. Nuestra prueba ya añade texto al campo de texto, por lo que sólo tenemos que añadir código para tocar el botón. Primero consideremos cómo encontrar el botón en la vista para que pueda ser tocado. Hay por lo menos tres maneras de lograr esto y cada enfoque tiene sus ventajas y desventajas.

Enfoque 1

Podemos tocar programáticamente una coordenada (X, Y) en la pantalla. Lo hacemos con la siguiente línea de código:

target.tap({x: 8.00, y: 50.00});

Por supuesto, no tengo ni idea de si esas son siquiera las coordenadas del botón en la pantalla y no me voy a preocupar por eso, porque este enfoque no es la herramienta adecuada para este trabajo. Sólo lo menciono para que sepas que existe. Usar el método tap en target para tocar un botón es propenso a errores, porque ese botón puede no estar siempre en esa coordenada específica.

Aproximación 2

También es posible encontrar el botón buscando en el array de botones de la ventana principal, de forma similar a como accedimos al campo de texto en la primera prueba. En lugar de acceder al botón directamente usando una clave, podemos recuperar un array de botones en la ventana principal y codificar un índice del array para obtener una referencia al botón.

target.frontMostApp().mainWindow().buttons().tap();

Este enfoque es un poco mejor. No estamos codificando una coordenada, sino que estamos codificando un índice de matriz para encontrar el botón. Si añadimos otro botón en la página, podemos romper accidentalmente esta prueba.

Enfoque 3

Esto me lleva a la tercera forma de encontrar el botón en la página, utilizando etiquetas de accesibilidad. Utilizando una etiqueta de accesibilidad, podemos acceder directamente al botón de la misma manera que encontraríamos un objeto en un diccionario utilizando una clave.

target.frontMostApp().mainWindow().buttons().tap();

Sin embargo, si añades la línea anterior al script y lo ejecutas, obtendrás un error.

Esto se debe a que aún no hemos definido la etiqueta de accesibilidad para el botón. Para ello, voltea a Xcode y abre el storyboard del proyecto. Busca el botón en la vista y abre el Inspector de Identidad de la derecha (Vista > Utilidades > Inspector de Identidad). Asegúrese de que la Accesibilidad está activada y establezca la Etiqueta para el botón como Botón Jumblify.

Para ejecutar la prueba de nuevo, tendrá que ejecutar la aplicación desde Xcode seleccionando Producto > Ejecutar y luego perfilar la aplicación de nuevo seleccionando Producto > Perfil. Esto ejecuta las pruebas y cada prueba debe pasar ahora.

Paso 5: Verificar la cadena desordenada

Como he mencionado anteriormente, nuestra aplicación toma una cadena de texto como entrada y, cuando el usuario toca el botón, muestra la cadena invertida. Tenemos que añadir una prueba más para verificar que la cadena de entrada se invierte correctamente. Para verificar que el UILabel se rellena con la cadena correcta, tenemos que averiguar cómo referenciar el UILabel y verificar la cadena que muestra. Este es un problema común cuando se escriben pruebas de automatización, es decir, averiguar cómo hacer referencia a un elemento en la aplicación para hacer una afirmación en él.

Hay un método en casi todos los objetos de la API de automatización de la interfaz de usuario, logElementTree. Este método registra los elementos anidados de un elemento dado. Esto es muy útil para entender la jerarquía de elementos en la aplicación y ayuda a averiguar cómo apuntar a un elemento específico.

Veamos cómo funciona esto registrando el árbol de elementos de la ventana principal. Echa un vistazo a la siguiente línea de código.

target.frontMostApp().mainWindow().logElementTree();

Añadir esta línea al script de prueba da como resultado la siguiente salida:

Como puedes ver, hay un subelemento UIAStaticText del UIAWindow y también puedes ver que tiene un nombre de ih, que también resulta ser la cadena invertida que necesitamos verificar. Ahora, para completar nuestra prueba, sólo tenemos que añadir código para acceder a este elemento y verificar que está presente.

¿Por qué sólo tenemos que verificar si el elemento UIAStaticText está presente? Porque el nombre del elemento es la cadena invertida de la cadena de entrada, verificar su presencia confirma que la cadena fue invertida correctamente. Si el elemento no existe cuando se hace referencia al nombre de la cadena invertida, significa que la cadena no se ha invertido correctamente. Raspando la superficie

Hay muchas otras formas en las que un usuario final puede interactuar con un dispositivo iOS mientras utiliza su aplicación. Esto significa que hay muchas otras formas en las que puedes utilizar la automatización de la interfaz de usuario para simular estas interacciones. En lugar de intentar capturar una lista completa de estas interacciones, te dirigiré a la documentación de referencia de UI Automation.

Para cada tipo de objeto con el que puedes interactuar, puedes ver la lista de métodos disponibles en ese objeto. Algunos métodos son para recuperar atributos sobre el objeto, mientras que otros son para simular la interacción táctil, como flickInsideWithOptions en UIAWindow.

Grabación de una sesión

A medida que intentas probar aplicaciones cada vez más complicadas con UI Automation, te darás cuenta de que a veces es bastante tedioso utilizar repetidamente logElementTree para encontrar el elemento que estás buscando. Esto también se vuelve tedioso y complejo para las aplicaciones con una jerarquía de vistas o una navegación compleja. En estos casos, puedes utilizar otra función de Instruments para registrar un conjunto de interacciones del usuario. Lo mejor es que Instruments genera el código JavaScript de automatización de la interfaz de usuario necesario para reproducir las interacciones grabadas. Así es como puedes probarlo por ti mismo.

En Instruments y con el instrumento de Automatización seleccionado, busca el botón de grabación en la parte inferior de la ventana.

Si haces clic en el botón de grabación, Instruments iniciará una sesión de grabación como se muestra en la siguiente captura de pantalla.

Instruments lanzará tu aplicación en el Simulador de iOS y podrás interactuar con ella. Instruments generará un script basado en tus interacciones en tiempo real. Pruébalo. Gira el simulador de iOS, toca en lugares aleatorios, realiza un gesto de deslizamiento, etc. Es una forma realmente útil de ayudar a explorar las posibilidades de la automatización de la interfaz de usuario.

Evitar una base de código monolítica

Como probablemente puedes prever, si seguimos añadiendo más pruebas al archivo de pruebas que hemos creado en el mismo método, rápidamente se volverá difícil de mantener. Qué podemos hacer para evitar que eso ocurra. En mis pruebas, hago dos cosas para resolver este problema:

  • Una prueba para una función: Esto implica que las pruebas que escribimos tienen que centrarse en una parte específica de la funcionalidad. Incluso le daré un nombre apropiado, como testEmptyInputField.
  • Agrupar pruebas relacionadas en un mismo archivo: También agrupo las pruebas relacionadas en el mismo archivo. Esto mantiene el código en un archivo manejable. Esto también hace que sea más fácil de probar piezas separadas de la funcionalidad mediante la ejecución de las pruebas en un archivo específico. Además, puedes crear un script maestro en el que llames a las funciones o pruebas que has agrupado en otros archivos de prueba.

En el siguiente fragmento de código, importamos un archivo JavaScript y esto hace que las funciones de ese archivo JavaScript estén disponibles para nosotros.

#import "OtherTests.js"

Conclusión

En este tutorial, has aprendido el valor de las pruebas de alto nivel y cómo la Automatización de la UI puede ayudar a llenar ese vacío. Es otra herramienta en su caja de herramientas para ayudar a garantizar el envío de aplicaciones fiables y robustas.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.