Les tests automatisés de l'interface utilisateur sont un sujet dont même les développeurs expérimentés se méfient. De plus, la technologie de ces tests n'est pas quelque chose d'extraordinaire, et dans le cas des tests d'interface utilisateur codés Visual Studio est une extension du système de test unitaire intégré Visual Studio Team Test. Dans cet article, je veux m'attarder sur le sujet des tests d'interface utilisateur en général, ainsi que sur notre expérience personnelle de l'utilisation des tests d'interface codés Visual Studio dans le travail sur l'analyseur statique PVS-Studio.
Les bases
Tout d'abord, essayons de comprendre pourquoi les tests d'interface utilisateur ne sont pas aussi populaires parmi les développeurs que, par exemple, les tests unitaires classiques.
Il existe de nombreuses «pyramides de test» sur le réseau qui montrent la distribution optimale recommandée du nombre de tests sur les couches d'application. Toutes les pyramides sont similaires et contiennent une idée générale: autant de tests que possible doivent être aussi proches que possible du code. Et vice versa. Je vais donner un exemple de l'une de ces pyramides, qui contient des recommandations supplémentaires sur le rapport du nombre de tests en pourcentage.

À la base de la pyramide se trouvent des tests unitaires. En effet, de tels tests sont plus faciles à faire au stade du développement, et ils seront exécutés très rapidement. Au sommet de la pyramide, d'autre part, se trouvent des tests d'interface automatisés. Ces tests ne devraient pas être nombreux, car la complexité de leur création, ainsi que le temps d'exécution, sont assez importants. De plus, il n'est pas clair à qui confier la création des tests d'interface utilisateur. En effet, nous parlons essentiellement d'émuler les actions des utilisateurs. Tout cela est très loin du code de l'application, les développeurs hésitent donc à faire ce genre de travail. Et pour effectuer des tests automatisés de haute qualité des interfaces sans la participation (ou avec une participation minimale) des programmeurs, l'utilisation d'outils payants est requise. La combinaison de tous ces facteurs conduit souvent au fait que les tests d'interface utilisateur ne font pas du tout, se limitant à un test manuel unique de nouvelles fonctionnalités. De plus, les tests d'interface sont extrêmement coûteux non seulement au stade du développement, mais également pendant le cycle de vie de l'application. Même un léger changement dans l'interface utilisateur peut entraîner des erreurs dans l'exécution de nombreux tests et la nécessité de les modifier.
Je note qu'à l'heure actuelle, notre système de test est en général conforme aux recommandations. Le nombre de tests GUI automatisés (45) représente environ un dixième du nombre total de tests PVS-Studio. Dans le même temps, le nombre de tests unitaires n'est pas si important, mais ils sont complétés par une multitude d'autres systèmes de test:
- Tests de performance des analyseurs (C / C ++ / C # / Java), au cours desquels ils vérifient un large pool de projets de test sur différents systèmes d'exploitation (Windows, Linux, macOS) et comparent les journaux des nouveaux avertissements avec les références;
- Tests de fonctionnalités spécifiques (suivi du lancement des compilateurs, etc.);
- Tests externes d'applications en ligne de commande;
- Tests d'assemblage, d'installation et de déploiement corrects;
- Tests de documentation.
Au stade initial de son développement, l'analyseur PVS-Studio était une application pour trouver des erreurs lors du portage de code C / C ++ vers une plate-forme 64 bits. Oui, et il a été appelé à cette époque d'une manière différente, "Viva64". L'historique du produit se trouve dans l'article "
Comment le projet PVS-Studio a commencé il y a 10 ans ". Après l'intégration dans Visual Studio 2005, l'analyseur a acquis une interface utilisateur graphique, essentiellement l'interface de l'IDE Visual Studio lui-même, dans laquelle, après l'installation du plug-in, un menu supplémentaire est apparu pour accéder à la fonctionnalité de l'analyseur. Le menu était composé de deux ou trois plats, il n'y avait donc rien à tester. Et Visual Studio à cette époque ne contenait aucun outil intégré pour tester les interfaces graphiques.
Tests et alternatives de l'interface utilisateur codée Visual Studio
Tout a changé avec la sortie de Visual Studio 2010, qui a introduit un système intégré pour créer des tests d'interface utilisateur: les tests d'interface codés Visual Studio (CUIT). Basé sur le système de test unitaire Visual Studio Team Test, CUIT a d'abord utilisé la technologie Microsoft Active Accessibility (MSAA) pour accéder aux éléments de l'interface visuelle. À l'avenir, la technologie a été améliorée et il s'agit actuellement d'un modèle développé d'automatisation de l'interface utilisateur pour tester le code UIA (UI Automation). Il permet au système de test d'accéder à des champs ouverts (nom d'objet, nom de classe interne de l'objet, état actuel de l'objet, sa place dans la structure hiérarchique de l'interface, etc.) des éléments COM et .NET UI, et le système vous permet d'émuler les effets sur ces éléments via des périphériques d'entrée standard (souris, clavier). Dès la sortie de la boîte, les modes d'enregistrement des actions des utilisateurs lors de l'interaction avec l'interface (similaires aux macros Visual Studio), l'automatisation de la construction d'une «carte d'interface» (propriétés des contrôles, paramètres de recherche et accès à ceux-ci), ainsi que la génération automatique du code de contrôle, sont pris en charge. À l'avenir, toutes les informations accumulées seront faciles à modifier et à maintenir à jour, ainsi qu'à personnaliser les séquences de test à votre guise, tout en ayant un minimum de compétences en programmation.
De plus, comme je l'ai dit plus tôt, maintenant lors de la création de tests d'interface utilisateur intelligents complexes, vous pouvez vous passer de compétences en programmation, à condition d'utiliser des outils payants spécialisés. Eh bien, s'il n'y a aucun désir ou capacité d'utiliser des environnements de test propriétaires, il existe de nombreux produits et frameworks gratuits. Le système de tests d'interface utilisateur codés Visual Studio est une solution intermédiaire qui permet non seulement d'automatiser autant que possible le processus de création de tests d'interface utilisateur. Avec son aide, il est facile de créer des séquences de test arbitraires dans les langages de programmation C # ou VB.
Tout cela peut réduire considérablement le coût de création et de maintien de la pertinence des tests GUI. Le cadre utilisé est simple à comprendre et peut en général être représenté sous forme de diagramme.
Parmi les éléments clés, notons les «adaptateurs d'interface», qui sont au niveau d'abstraction le plus bas. Cette couche interagit avec les éléments finis de l'interface utilisateur et ses capacités peuvent être étendues à l'aide d'adaptateurs supplémentaires. Ci-dessus, une couche qui masque les technologies d'accès à l'interface graphique du reste du code, y compris les interfaces d'accès au programme et le code d'application de test réel, qui comprend tous les éléments nécessaires pour tester l'automatisation. La technologie est extensible, chaque niveau peut être complété par les éléments nécessaires dans le cadre du cadre.
Les principales fonctionnalités de CUIT de Microsoft incluent:
- Test fonctionnel des interfaces utilisateurs. Applications, applications Web et services classiques basés sur Windows, WPF sont pris en charge
- Génération de code (y compris automatique) en VB / C #
- Capacité à s'intégrer dans le processus d'assemblage
- Lancements locaux ou distants, collecte de rapports
- Disponibilité des séquences de test d'enregistrement et de reproduction
- Bonne extensibilité
Malgré un certain nombre de difficultés associées à CUIT, l'utilisation de cette technologie de test est préférée pour un certain nombre de raisons:
- Interaction efficace des développeurs et des testeurs au sein d'un même outil et langage de programmation
- Fonctionnalités supplémentaires de travail avec la «carte d'interface», permettant l'identification des commandes «à la volée», la synchronisation des éléments et l'achèvement des séquences de test
- Réglage fin du mécanisme de lecture, qui permet avec des paramètres de base, tels qu'un délai entre les opérations, un délai de recherche d'élément, etc., d'utiliser des mécanismes spécialisés dans le code. Par exemple, verrouiller le thread actuel jusqu'à ce que le contrôle soit activé (visualisé) à l'aide des méthodes WaitForControlExist ou WaitForReady avec l'énumération WaitForReadyLevel , etc.
- Possibilité de programmer des tests complexes et illimités
Je n'entrerai pas plus loin dans les aspects théoriques de la technologie des tests d'interface utilisateur codés Visual Studio, ils sont tous détaillés dans la documentation pertinente. Vous y trouverez des instructions détaillées étape par étape pour créer le test d'interface utilisateur le plus simple basé sur ce système. Et oui, le système n'est pas gratuit, vous aurez besoin de Visual Studio Enterprise pour travailler avec.
La technologie décrite n'est pas la seule sur le marché. Il existe de nombreuses autres solutions. Tous les autres systèmes de test d'interface utilisateur peuvent être divisés en payants et gratuits. De plus, le choix d'un système particulier ne dépendra pas toujours de son prix. Par exemple, la possibilité de créer des tests sans avoir besoin de programmation peut être un facteur important, mais en même temps, les tests peuvent ne pas être suffisamment flexibles. Il est également important de prendre en charge l'environnement de test nécessaire - systèmes d'exploitation et applications. Enfin, les fonctionnalités purement spécifiques de l'application et de son interface peuvent influencer le choix. Voici quelques systèmes et technologies populaires pour tester les interfaces graphiques.
Payé :
TestComplete (SmartBear),
Test fonctionnel unifié (Micro Focus),
Squish (froglogic),
Outils de test automatisé (Ranorex),
Aubergine fonctionnelle (aubergine), etc.
Gratuit :
AutoIt (windows),
Selenium (web),
Katalon Studio (web, mobile),
Sahi (web),
Robot Framework (web),
LDTP (Linux Desktop Testing Project), Framework open source:
TestStack.White +
UIAutomationVerify,. Bibliothèque d'automatisation NET Windows , etc.
Bien sûr, cette liste n'est pas complète. Cependant, il est évident que les systèmes gratuits sont généralement axés sur un système d'exploitation ou une technologie de test spécifique. La règle générale est que parmi les systèmes payants, vous trouverez beaucoup plus rapidement quelque chose qui convient spécifiquement à vos besoins, le développement et la maintenance des tests seront plus faciles et la liste des environnements de test pris en charge est exhaustive.
Dans notre cas, il n'y avait pas de problème de choix: avec la sortie de Visual Studio 2010 avec l'ajout de tests d'interface codés, il est devenu possible d'ajouter facilement un ensemble de tests fonctionnels à notre environnement de test pour tester l'interface utilisateur du plug-in PVS-Studio pour Visual Studio.
Tests d'interface utilisateur PVS-Studio
Les tests GUI de notre entreprise sont donc utilisés depuis plus de 6 ans. L'ensemble initial de tests d'interface utilisateur pour Visual Studio 2010 était basé sur la seule technologie MSAA (Microsoft Active Accessibility) disponible à l'époque. Avec la sortie de Visual Studio 2012, la technologie MSAA s'est considérablement développée et s'appelle désormais UIA (UI Automation). Il a été décidé de continuer à utiliser l'UIA et de laisser les tests basés sur MSAA pour tester le plug-in pour Visual Studio 2010 (nous prenons en charge et testons les plug-ins pour toutes les versions de Visual Studio, à partir de Visual Studio 2010).
En conséquence, nous avons formé deux «branches» de tests d'interface utilisateur. De plus, dans le projet de test, ces deux branches ont utilisé une carte d'interface commune et un code partagé. Dans le code, cela ressemblait à ceci (méthode pour réinitialiser les paramètres de Visual Studio aux normes avant d'exécuter le test):
public void ResetVSSettings(TestingMode mode) { .... #region MSAA Mode if (mode == TestingMode.MSAA) { .... return; } #endregion
Lors de la modification de l'interface du plugin, il était nécessaire d'apporter des modifications aux deux branches des tests d'interface utilisateur, et l'ajout de nouvelles fonctionnalités a rendu nécessaire la duplication de l'élément d'interface dans la carte: c'est-à-dire, créer deux éléments différents pour chacune des technologies MSAA et UIA. Tout cela a exigé beaucoup d'efforts non seulement pour créer ou modifier des tests, mais aussi pour maintenir l'environnement de test dans un état stable. Je m'attarderai sur cet aspect plus en détail.
Selon mes observations, la stabilité de l'environnement de test lors du test de l'interface graphique est un problème important. Cela est principalement dû à la forte dépendance de ces tests à de nombreux facteurs externes. En effet, en fait, les actions de l'utilisateur sont émulées: appui sur les touches, déplacement du curseur de la souris, clics de souris, etc. Il y a beaucoup de choses qui peuvent «mal tourner». Par exemple, si pendant le test, quelqu'un interagit avec un clavier connecté au serveur de test. De plus, de façon inattendue, la résolution du moniteur peut ne pas être suffisante pour afficher un contrôle, et elle ne sera pas trouvée par l'environnement de test.
En attente:
Réalité:
Un élément de carte d'interface négligemment réglé (et non trouvé plus tard) est pratiquement le leader du comportement problématique. Par exemple, lors de la création d'un nouveau contrôle, l'assistant de mappage d'interface des tests de l'interface utilisateur codée de Visual Studio utilise les critères de recherche Égal par défaut pour celui-ci. En d'autres termes, une correspondance exacte des noms de propriété aux valeurs spécifiées est requise. Cela fonctionne généralement, mais parfois la stabilité de l'exécution des tests peut être considérablement améliorée en utilisant les critères de recherche moins stricts «Contient» au lieu de «Égal». Ceci est juste un exemple de "tweak" que vous pouvez rencontrer lorsque vous travaillez sur des tests d'interface utilisateur.
Enfin, certains de vos tests peuvent consister à effectuer une action et à attendre un résultat, qui est par exemple associé à l'affichage d'une fenêtre. Dans ce cas, au problème de la recherche d'un élément, des questions de réglage du délai de lecture jusqu'à l'apparition de la fenêtre puis de synchronisation du travail seront ajoutées. Certains de ces problèmes peuvent être résolus par des méthodes de framework standard (
WaitForControlExist , etc.), tandis que pour d'autres, il sera nécessaire d'inventer des algorithmes ingénieux.
Nous avons rencontré un problème similaire en travaillant sur l'un des tests de notre plugin. Dans ce test, un environnement Visual Studio vide est ouvert en premier, puis une certaine solution de test y est chargée, qui est entièrement testée à l'aide de PVS-Studio (menu «PVS-Studio» -> «Vérifier» -> «Solution»). Le problème était de déterminer quand la vérification serait terminée. Selon un certain nombre de conditions, la vérification peut ne pas toujours prendre le même temps, les délais d'attente simples ne fonctionnent donc pas ici. En outre, vous ne pouvez pas utiliser les mécanismes standard pour suspendre le flux de test et attendre l'apparition (ou le masquage) d'un contrôle, car il n'y a rien à attacher. Pendant la vérification, une fenêtre avec le statut de travail apparaît, mais cette fenêtre peut être masquée, et la vérification continuera. C'est-à-dire cette fenêtre ne peut pas être guidée (en plus, elle a le réglage «Ne pas fermer une fois l'analyse terminée»). Et je voulais rendre l'algorithme plus général afin de l'utiliser pour différents tests liés à la vérification des projets et en attendant la fin de ce processus. Une solution a été trouvée. Après le démarrage du test et jusqu'à son achèvement, l'élément de menu même «PVS-Studio» -> «Vérifier» -> «Solution» est inactif. Nous n'avions qu'à vérifier la propriété «Enabled» de cet élément de menu à un certain intervalle de temps (via l'objet de carte d'interface) et, s'il était constaté que l'élément était devenu actif, considérer le processus de vérification de décision comme terminé.
Ainsi, dans le cas des tests d'interface utilisateur, il ne suffit pas de simplement créer des tests. Un réglage subtil et minutieux est requis dans chaque cas. Il est nécessaire de comprendre et de synchroniser la séquence complète des actions effectuées. Par exemple, l'élément de menu contextuel ne sera pas trouvé tant que ce menu ne sera pas affiché à l'écran, etc. Une préparation minutieuse de l'environnement de test est également requise. Dans ce cas, vous pouvez compter sur le fonctionnement stable des tests et des résultats adéquats.
Permettez-moi de vous rappeler que le système de tests d'interface utilisateur dans notre entreprise se développe depuis 2010. Pendant ce temps, plusieurs dizaines de séquences de test ont été créées et de nombreux codes auxiliaires ont été écrits. Des tests d'application autonomes ont été ajoutés aux tests de plugin au fil du temps. À ce stade, l'ancienne branche de test de plug-in pour Visual Studio 2010 avait perdu sa pertinence et a été abandonnée, mais il était tout simplement impossible de supprimer ce code «mort» du projet. Premièrement, comme je l'ai montré précédemment, le code a été assez profondément intégré dans les méthodes de test. Et deuxièmement, plus de la moitié des éléments de la carte d'interface existante appartenaient à l'ancienne technologie MSAA, mais ont été réutilisés (au lieu de duplication) dans de nombreux nouveaux tests avec des éléments UIA (cela est possible en raison de la continuité de la technologie). Dans le même temps, la masse du code généré automatiquement et du contenu des méthodes de test était liée aux "anciens" éléments.
À l'automne 2017, il était nécessaire d'améliorer le système de tests d'interface utilisateur. En général, les tests ont bien fonctionné, mais de temps en temps certains tests ont "planté" pour des raisons inconnues. Plus précisément, la raison était généralement de trouver un contrôle. Dans chaque cas, j'ai dû parcourir l'arborescence de la carte d'interface jusqu'à un élément spécifique et vérifier ses critères de recherche et d'autres paramètres. Parfois, une réinitialisation logicielle de ces paramètres a aidé avant d'exécuter le test. Étant donné la carte d'interface qui s'est développée (et à bien des égards, à bien des égards) par la carte d'interface, ainsi que la présence de code "mort", ce processus a nécessité des efforts considérables.
Depuis quelque temps, la tâche «attendait son héros», jusqu'à ce qu'elle vienne enfin à moi.
Je ne vous ennuierai pas avec une description des nuances. Je peux seulement dire que le travail n'a pas été difficile, mais il a nécessité beaucoup de persévérance et d'attention. Tout sur tout m'a pris environ deux semaines. J'ai passé la moitié de ce temps à refactoriser le code et les cartes d'interface. Dans le temps restant, il s'est engagé dans la stabilisation de l'exécution des tests, qui se résumait essentiellement à un réglage plus fin des critères de recherche des éléments visuels (modification de la carte d'interface), ainsi qu'à une certaine optimisation du code.
En conséquence, nous avons réussi à réduire la taille du code des méthodes de test d'environ 30% et le nombre de contrôles dans l'arborescence de la carte d'interface a été divisé par deux. Mais surtout, les tests d'interface utilisateur ont commencé à montrer des performances plus stables et nécessitent moins d'attention. Et la chute a commencé à se produire plus souvent pour des raisons de modification de la fonctionnalité de l'analyseur ou lors de la détection d'incohérences (erreurs). En fait, à ces fins, nous avons besoin d'un système de tests d'interface utilisateur.
Ainsi, à l'heure actuelle, le système de tests automatiques de l'interface PVS-Studio présente les caractéristiques de base suivantes:
- Test d'interface utilisateur codé Visual Studio
- 45 scénarios
- 4 095 lignes de code pour les méthodes d'essai
- 19 889 lignes de code généré automatiquement (à l'exclusion de la taille du fichier xml pour le stockage des paramètres de carte d'interface utilisateur)
- 1 heure 34 minutes d'exécution (valeur moyenne en fonction des résultats des 30 derniers démarrages)
- Travailler sur un serveur dédié (exécutant l'utilitaire MSTest.exe)
- Surveillance des performances et analyse des rapports de performances (Jenkins)
Conclusion
En conclusion, je veux donner une liste de critères de réussite pour les tests GUI automatiques, qui est basée sur une analyse de notre expérience avec cette technologie (certains des critères s'appliquent à d'autres technologies de test, par exemple, les tests unitaires).
Outils appropriés . Choisissez l'environnement de création et d'exécution de CUIT en fonction des fonctionnalités de votre application, ainsi que de l'environnement de test. Les solutions payantes n'ont pas toujours de sens, mais elles aident généralement à résoudre un problème très efficacement.
Configuration d'infrastructure de haute qualité . Ne pas enregistrer lors du développement d'une carte d'interface. Simplifiez le travail du framework lors de la recherche d'éléments en décrivant soigneusement toutes leurs propriétés et en définissant des critères de recherche intelligents. Faites attention aux possibilités de modifications supplémentaires.
Minimisation du travail manuel . Dans la mesure du possible, assurez-vous d'utiliser des moyens automatiques pour générer du code et enregistrer des séquences. Ainsi, vous accélérerez considérablement le développement et minimiserez la probabilité d'erreurs (il n'est pas toujours facile de trouver la raison du plantage du test d'interface utilisateur, surtout si une erreur est commise dans le code pour travailler avec le framework).
Tests intelligents simples et indépendants . Plus vos tests sont simples, mieux c'est. Essayez de faire un test distinct pour tester un contrôle spécifique ou une situation simulée. Assurez-vous également que les tests sont indépendants les uns des autres. La chute d'un des tests ne devrait pas affecter l'ensemble du processus.
Noms amicaux . Utilisez des préfixes dans les noms de tests similaires. De nombreux environnements vous permettent d'exécuter des tests en filtrant par nom. Utilisez également le regroupement de tests dans la mesure du possible.
Exécution isolée . Assurez-vous que les tests sont exécutés sur un serveur dédié avec un impact externe minimal. Déconnectez tous les périphériques d'entrée utilisateur externes, fournissez la résolution d'écran nécessaire à votre application ou utilisez un mannequin matériel qui simule une connexion de moniteur haute résolution. Assurez-vous qu'au cours du test, les autres applications qui interagissent, par exemple avec le bureau et affichent les messages, ne sont pas en cours d'exécution. Il est également nécessaire de planifier l'heure de début et de considérer la durée maximale des tests.
Analyse des rapports publiés . Fournissez un formulaire simple et clair pour rendre compte des progrès. Utilisez des systèmes d'intégration continue pour envoyer les tests, ainsi que pour obtenir et analyser rapidement les résultats des tests.

Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien vers la traduction: Sergey Khrenov.
Tests d'interface utilisateur codés Visual Studio: théorie et expérience utilisateur de notre entreprise