Introduction aux tests iOS avec UI Automation

Avr 17, 2021
admin

Imaginez simplement pouvoir écrire des scripts qui interagissent automatiquement avec votre application iOS et pouvoir vérifier les résultats. Avec UI Automation, c’est possible. UI Automation est un outil fourni par Apple pour effectuer un niveau supérieur de test sur votre application iOS au-delà de tout ce qui est réalisable avec XCTest.

1. Test boîte blanche versus boîte noire

Vous avez peut-être entendu la comparaison entre le test boîte blanche et le test boîte noire en ce qui concerne la façon dont on pourrait tester un logiciel. Si vous n’êtes pas familier avec ces concepts, laissez-moi vous expliquer comment ils fonctionnent.

Test en boîte blanche

Imaginez qu’il y a un logiciel qui fonctionne à l’intérieur d’une boîte. Avec le test de la boîte blanche, vous pouvez voir à l’intérieur de la boîte et regarder toutes les pièces granuleuses de la façon dont le logiciel fonctionne, puis prendre des décisions éclairées sur la façon de tester le logiciel. Vous pouvez également avoir des crochets de niveau plus profond dans le logiciel à partir des tests que vous écrivez.

Les tests unitaires sont des tests en boîte blanche. Lors de l’écriture de tests unitaires, le testeur a un accès fin au code testé. Le testeur peut en fait écrire des tests qui exploitent le logiciel testé au niveau de la méthode, ou de l’unité.

Dans le développement de logiciels iOS, nous utilisons le framework XCTest pour effectuer ce type de tests. Jetez un coup d’œil à un autre tutoriel que j’ai écrit sur le démarrage avec XCTest.

Test de boîte noire

Dans le test de boîte noire, la boîte est opaque. Le testeur ne peut pas voir à l’intérieur de la boîte. Le testeur ne peut pas accéder et ne connaît pas l’implémentation de la base de code pour écrire des tests. Au lieu de cela, le testeur est forcé d’utiliser l’application comme le ferait un utilisateur final en interagissant avec l’application et en attendant sa réponse, en vérifiant les résultats.

Il y a au moins deux façons d’exécuter ce type de test.

  • Un testeur qui effectue de manière répétée et manuelle un certain nombre d’étapes prédéfinies et vérifie visuellement les résultats.
  • Utiliser des outils spécialisés pour tester l’application avec des API qui se comportent de manière similaire à la façon dont un humain interagit.

Dans le développement d’applications iOS, Apple fournit un outil appelé UI Automation pour effectuer des tests de boîte noire.

2. Qu’est-ce que UI Automation ?

UI Automation est un outil qu’Apple fournit et maintient pour des tests de plus haut niveau, automatisés, des applications iOS. Les tests sont écrits en JavaScript, en adhérant à une API définie par Apple.

L’écriture des tests peut être facilitée en s’appuyant sur les étiquettes d’accessibilité des éléments d’interface utilisateur de votre application. Ne vous inquiétez pas cependant, si vous ne les avez pas définis, il existe des alternatives disponibles.

L’API d’automatisation de l’interface utilisateur ne dispose pas du format typique basé sur xUnit pour écrire des tests. Une différence avec les tests unitaires est que le testeur doit consigner manuellement les succès et les échecs. Les tests UI Automation sont exécutés à partir de l’instrument Automation dans l’outil Instruments fourni avec les outils de développement d’Apple. Les tests peuvent être exécutés dans le simulateur iOS ou sur un appareil physique.

3. Écrire des tests d’automatisation de l’interface utilisateur

Étape 1 : Ouvrir le projet d’exemple

J’ai mis à jour le projet d’exemple utilisé dans le tutoriel précédent sur les tests iOS avec quelques éléments d’interface utilisateur supplémentaires qui fournissent quelques crochets utiles pour ajouter des tests d’automatisation de l’interface utilisateur. Téléchargez le projet depuis GitHub. Ouvrez le projet et exécutez l’application pour vous assurer que tout fonctionne comme prévu. Vous devriez voir une interface utilisateur similaire à celle présentée ci-dessous.

Avant d’écrire des tests, n’hésitez pas à essayer l’application d’exemple pour vous familiariser avec ses fonctionnalités. En tant qu’utilisateur, vous pouvez saisir du texte dans le champ de texte et toucher le bouton pour voir une étiquette à l’écran qui affiche la chaîne saisie inversée.

Étape 2 : créer un test d’automatisation de l’interface utilisateur

Maintenant que vous êtes familiarisé avec l’application d’exemple, il est temps d’ajouter un test d’automatisation de l’interface utilisateur. UI Automation est un outil que l’on peut trouver dans Instruments. Pour exécuter l’application d’exemple dans Instruments, sélectionnez Produit > Profil dans le menu de Xcode. Sélectionnez Automation dans la liste des outils.

La fenêtre principale d’Instruments s’ouvre avec un seul instrument prêt à fonctionner, l’instrument Automation (l’instrument Automation exécute les cas de test UI Automation). Vous verrez également une zone dans la moitié inférieure de la fenêtre qui ressemble à un éditeur de texte. Il s’agit de l’éditeur de script. C’est là que vous allez écrire vos tests d’automatisation de l’interface utilisateur. Pour ce premier test, suivez les instructions ci-dessous, en ajoutant chaque ligne au script dans l’éditeur de script.

Débutez en stockant une référence au champ de texte dans une variable.

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

Définissez la valeur du champ de texte.

inputField.setValue("hi");

Vérifiez que la valeur a été définie avec succès et, si c’est le cas, passez le test. Échouer le test si ce n’est pas le cas.

Bien que ce test soit assez trivial, il a une valeur. Nous venons d’écrire un test qui teste la présence d’un champ texte au lancement de l’application et qui teste si une chaîne aléatoire peut être définie comme valeur du champ texte. Si vous ne me croyez pas, supprimez le champ de texte du storyboard et exécutez le test. Vous verrez qu’il échoue.

Ce test démontre trois éléments importants de l’écriture de tests UI Automation. Premièrement, il vous montre comment accéder à un élément simple de l’interface utilisateur, le champ de texte. Plus précisément, nous accédons à un dictionnaire de tous les champs de texte sur la vue de base de l’application via target.frontMostApp().mainWindow().textFields() et nous trouvons ensuite le champ de texte qui nous intéresse en recherchant celui qui a la clé Input Field. Cette clé est en fait l’étiquette d’accessibilité du champ de texte. Dans ce cas, elle est définie dans le storyboard. Nous pouvons également définir l’étiquette d’accessibilité dans le code en utilisant la propriété accessibilityLabel sur NSObject.

Accéder à la fenêtre principale de l’application, à l’application la plus en avant et à la cible est courant lorsqu’on travaille avec UI Automation. Je vous montrerai comment rendre cela plus facile et moins verbeux plus tard dans ce tutoriel.

En second lieu, cela vous montre que vous pouvez interagir avec les éléments de l’interface utilisateur sur l’écran. Dans ce cas, nous définissons la valeur du champ de texte, imitant l’utilisateur qui interagit avec l’application en saisissant du texte dans le champ de texte.

Et troisièmement, l’exemple montre également une technique pour vérifier ce qui se passe dans l’application. Si la valeur est définie avec succès, le test passe. Si la valeur n’est pas définie, le test échoue.

Etape 3 : Enregistrement des tests

Bien que l’écriture des tests dans l’éditeur de script soit pratique, elle devient rapidement encombrante et difficile à maintenir. Si vous quittez Instruments, toutes les modifications non sauvegardées sont abandonnées. Nous avons besoin de sauvegarder les tests que nous écrivons. Il suffit de copier et coller votre test dans un nouveau document de votre éditeur de texte préféré et de l’enregistrer. Vous pouvez trouver les tests créés dans ce tutoriel dans le projet d’exemple sous Jumblify/JumblifyTests/AutomationTests.js.

Pour exécuter le test, sélectionnez l’onglet du milieu dans le volet de droite, à côté de l’éditeur de script, et sélectionnez Ajouter > Importer.

Vous serez invité à sélectionner le script à importer. Naviguez jusqu’au script enregistré et importez-le. Vous pouvez toujours modifier le script dans l’éditeur de script. Toutes les modifications seront automatiquement enregistrées dans le fichier externe que vous avez créé.

Étape 4 : Taper sur un bouton

Mettons à jour notre test pour tester l’interaction avec le bouton. Notre test ajoute déjà du texte dans le champ de texte, donc nous devons seulement ajouter du code pour taper sur le bouton. Considérons d’abord comment trouver le bouton dans la vue afin de pouvoir l’effleurer. Il y a au moins trois façons d’accomplir cela et chaque approche a ses compromis.

Approche 1

Nous pouvons taper programmatiquement sur une coordonnée (X, Y) sur l’écran. Nous le faisons avec la ligne de code suivante :

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

Bien sûr, je n’ai aucune idée si ce sont même les coordonnées du bouton sur l’écran et je ne vais pas m’en inquiéter, car cette approche n’est pas le bon outil pour ce travail. Je la mentionne seulement pour que vous sachiez qu’elle existe. Utiliser la méthode tap sur target pour taper sur un bouton est source d’erreurs, parce que ce bouton peut ne pas toujours être à cette coordonnée spécifique.

Approche 2

Il est également possible de trouver le bouton en cherchant dans le tableau des boutons de la fenêtre principale, de la même façon que nous avons accédé au champ de texte dans le premier test. Au lieu d’accéder directement au bouton en utilisant une clé, nous pouvons récupérer un tableau de boutons sur la fenêtre principale et coder en dur un index de tableau pour obtenir une référence au bouton.

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

Cette approche est un peu meilleure. Nous ne codons pas en dur une coordonnée, mais nous codons en dur un indice de tableau pour trouver le bouton. Si nous arrivons à ajouter un autre bouton sur la page, cela peut accidentellement casser ce test.

Approche 3

Cela m’amène à la troisième façon de trouver le bouton sur la page, en utilisant les étiquettes d’accessibilité. En utilisant une étiquette d’accessibilité, nous pouvons accéder directement au bouton tout comme nous trouverions un objet dans un dictionnaire en utilisant une clé.

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

Cependant, si vous ajoutez la ligne ci-dessus au script et l’exécutez, vous obtiendrez une erreur.

C’est parce que nous n’avons pas encore défini l’étiquette d’accessibilité pour le bouton. Pour ce faire, basculez dans Xcode et ouvrez le storyboard du projet. Trouvez le bouton dans la vue et ouvrez l’inspecteur d’identité sur la droite (Vue > Utilitaires > Inspecteur d’identité). Assurez-vous que l’accessibilité est activée et définissez l’étiquette du bouton sur Jumblify Button.

Pour exécuter à nouveau le test, vous devrez exécuter l’application depuis Xcode en sélectionnant Produit > Exécuter, puis profiler à nouveau l’application en sélectionnant Produit > Profil. Cela exécute les tests et chaque test devrait passer maintenant.

Étape 5 : Vérifier la chaîne de caractères mélangée

Comme je l’ai mentionné précédemment, notre application prend une chaîne de texte en entrée et, lorsque l’utilisateur tape sur le bouton, affiche la chaîne inversée. Nous devons ajouter un test supplémentaire pour vérifier que la chaîne d’entrée est correctement inversée. Pour vérifier que la UILabel est remplie avec la bonne chaîne, nous devons trouver comment référencer la UILabel et vérifier la chaîne qu’elle affiche. C’est un problème courant lors de l’écriture de tests d’automatisation, c’est-à-dire trouver comment référencer un élément de l’application pour faire une assertion sur celui-ci.

Il existe une méthode sur presque chaque objet de l’API d’automatisation de l’interface utilisateur, logElementTree. Cette méthode consigne les éléments imbriqués d’un élément donné. Ceci est très utile pour comprendre la hiérarchie des éléments dans l’application et aide à comprendre comment cibler un élément spécifique.

Voyons comment cela fonctionne en consignant l’arbre des éléments de la fenêtre principale. Jetez un coup d’œil à la ligne de code suivante.

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

Ajouter cette ligne au script de test donne la sortie suivante:

Comme vous pouvez le voir, il y a un sous-élément UIAStaticText du UIAWindow et vous pouvez également voir qu’il a un nom de ih, qui se trouve également être la chaîne inversée que nous devons vérifier. Maintenant, pour compléter notre test, nous devons juste ajouter du code pour accéder à cet élément et vérifier qu’il est présent.

Pourquoi devons-nous seulement vérifier si l’élément UIAStaticText est présent ? Parce que le nom de l’élément est la chaîne inversée de la chaîne d’entrée, la vérification de sa présence confirme que la chaîne a été correctement inversée. Si l’élément n’existe pas lorsqu’il est référencé par son nom – la chaîne inversée – cela signifie que la chaîne n’a pas été correctement inversée.

4. Gratter la surface

Il y a tellement d’autres façons dont un utilisateur final peut interagir avec un appareil iOS tout en utilisant votre application. Cela signifie qu’il existe de nombreuses autres façons d’utiliser l’automatisation de l’interface utilisateur pour simuler ces interactions. Plutôt que de tenter de capturer une liste exhaustive de ces interactions, je vais vous diriger vers la documentation de référence de UI Automation.

Pour chaque type d’objet avec lequel vous pouvez interagir, vous pouvez afficher la liste des méthodes disponibles sur cet objet. Certaines méthodes permettent de récupérer les attributs de l’objet tandis que d’autres permettent de simuler l’interaction tactile, comme flickInsideWithOptions sur UIAWindow.

Enregistrer une session

A mesure que vous tentez de tester des applications de plus en plus compliquées avec UI Automation, vous constaterez qu’il est parfois assez fastidieux d’utiliser à plusieurs reprises logElementTree pour trouver l’élément que vous recherchez. Cela devient également fastidieux et complexe pour les applications avec une hiérarchie de vues ou une navigation complexe. Dans ces cas, vous pouvez utiliser une autre fonctionnalité d’Instruments pour enregistrer un ensemble d’interactions utilisateur. Ce qui est encore plus cool, c’est qu’Instruments génère le code JavaScript d’automatisation de l’interface utilisateur qui est nécessaire pour reproduire les interactions enregistrées. Voici comment vous pouvez l’essayer par vous-même.

Dans Instruments et avec l’instrument Automation sélectionné, recherchez le bouton d’enregistrement en bas de la fenêtre.

Si vous cliquez sur le bouton d’enregistrement, Instruments démarrera une session d’enregistrement comme indiqué dans la capture d’écran ci-dessous.

Instruments lancera votre application dans le simulateur iOS et vous pourrez interagir avec elle. Instruments va générer un script basé sur vos interactions en temps réel. Essayez-le. Faites pivoter le simulateur iOS, tapez à des endroits aléatoires, effectuez un geste de balayage, etc. C’est un moyen vraiment utile pour aider à explorer les possibilités de l’automatisation de l’interface utilisateur.

Éviter une base de code monolithique

Comme vous pouvez probablement le prévoir, si nous continuons à ajouter plus de tests au fichier de test que nous avons créé dans la même méthode, il deviendra rapidement difficile à maintenir. Que pouvons-nous faire pour éviter que cela ne se produise. Dans mes tests, je fais deux choses pour résoudre ce problème :

  • Un test pour une fonction : Cela implique que les tests que nous écrivons doivent se concentrer sur une pièce spécifique de la fonctionnalité. Je vais même lui donner un nom approprié, comme testEmptyInputField.
  • Regrouper les tests connexes dans un seul fichier : Je regroupe également les tests connexes dans le même fichier. Cela permet de gérer le code dans un seul fichier. Cela permet également de tester plus facilement des éléments de fonctionnalité distincts en exécutant les tests dans un fichier spécifique. En outre, vous pouvez créer un script maître dans lequel vous appelez les fonctions ou les tests que vous avez regroupés dans d’autres fichiers de test.

Dans l’extrait de code suivant, nous importons un fichier JavaScript et cela met à notre disposition les fonctions de ce fichier JavaScript.

#import "OtherTests.js"

Conclusion

Dans ce tutoriel, vous avez appris la valeur des tests de niveau supérieur et comment UI Automation peut aider à combler cette lacune. C’est un autre outil dans votre boîte à outils pour vous assurer que vous expédiez des applications fiables et robustes.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.