Au lieu de 100 lancements d'applications - un autotest, ou comment sauver un ingénieur QA 20 ans de vie

Bonjour à tous, je m'appelle Evgeny Demidenko. Depuis quelques années, je développe un système de test de jeu automatisé chez Pixonic. Aujourd'hui, je voulais partager notre expérience dans le développement, le support et l'utilisation d'un tel système sur le projet War Robots.

Pour commencer, nous allons découvrir ce que nous automatisons avec ce système.

Tout d'abord, ce sont les tests d'interface de régression, les tests du gameplay de base et l'automatisation des benchmarks. Les trois systèmes dans leur ensemble permettent de réduire la charge du service AQ avant les versions, d'être plus confiants dans le refactoring à grande échelle et en profondeur, et de maintenir constamment une évaluation globale des performances de l'application, ainsi que de ses différentes parties. Un autre point que je veux noter est l'automatisation de la routine, par exemple - le test de toute hypothèse.

image

Je vais vous donner quelques chiffres. Maintenant, plus de 600 tests d'interface utilisateur et environ 100 tests de base ont été écrits pour les robots de guerre. Sur ce seul projet, nous avons effectué environ un million de lancements de nos scripts de test, dont chacun a pris environ 80 secondes. Si nous avions vérifié ces scénarios manuellement, nous aurions passé au moins cinq minutes chacun. De plus, nous avons lancé plus de 700 000 benchmarks.

Parmi les plateformes, nous utilisons Android et iOS - seulement 12 appareils dans le parc. Deux programmeurs sont impliqués dans le développement et le support du système, et un ingénieur QA écrit et analyse les tests.






Quant à la pile logicielle, nous utilisons NUnit dans notre base de données, mais pas pour les tests unitaires, mais pour les tests d'intégration et de système. Pour le gameplay de base et les tests de vérification de build, nous utilisons la solution intégrée d'Unity - Unity Test Tools. Pour rédiger et analyser des rapports après ces tests, le rapport de test Allure de Yandex est utilisé, ainsi que TeamCity - comme système d'intégration continue pour la création d'applications, le déploiement de serveurs et l'exécution de tests. Nous utilisons le référentiel Nexus et la base de données PostgreSQL pour stocker nos artefacts.




Comment créer, analyser et exécuter des tests


Supposons que nous voulons écrire un test simple qui, dans la fenêtre des paramètres du jeu, vérifiera l'icône pour activer et désactiver le son.

Nous avons donc écrit un test et l'avons validé dans une branche spécifique de notre référentiel de tests. Nous avons choisi les tests que nous voulons exécuter, choisi une build à exécuter, ou peut-être un commit spécifique, sur lequel la build sera assemblée. Exécutez maintenant le test, attendez un moment et obtenez le résultat.





Dans ce cas, 575 tests ont été lancés, dont 97% ont réussi. Il nous a fallu environ trois heures pour terminer tous les tests. À titre de comparaison, les mêmes tests, s'ils étaient effectués manuellement, prendraient au moins 50 heures de fonctionnement continu.

Alors, qu'est-il arrivé à ces 3% des tests qui ont échoué?

Nous ouvrons un test spécifique et voyons un message indiquant qu'une erreur s'est produite lors de la correspondance des captures d'écran.



Ensuite, nous ouvrons la capture d'écran, qui était à ce moment sur l'appareil, et nous voyons que les zones qui ne correspondent pas à l'original sont marquées avec des pixels rouges. A titre de comparaison, nous lui donnons.





Naturellement, après cela, l'ingénieur QA doit soit faire un bug pour que le comportement de la construction ne corresponde pas au document de conception de jeu, soit mettre à jour les captures d'écran originales, car le document de conception de jeu a changé, et maintenant ces éléments ne seront plus dans le jeu.


Ça a l'air cool. Pourquoi tout cela est-il nécessaire?


Il y a quelque temps, sur le projet War Robots, nous devions faire une petite refactorisation. Elle consistait à réécrire quelques morceaux de code pour tirer des armes - en particulier des mitrailleuses.

Lors des tests, nous avons trouvé une nuance intéressante: le taux de mitrailleuses dépendait directement du FPS. Un tel bogue serait irréaliste à détecter lors des tests manuels: d'une part, en raison des caractéristiques du calcul réseau des dommages sur le projet, et d'autre part, du fait que l'application War Robots est assez bien optimisée et à ce moment-là, elle fonctionnait sur tous appareils avec approximativement le même FPS - 30 images / s. Bien sûr, il y avait de petites déviations, mais elles n'étaient pas suffisantes pour remarquer une augmentation des dommages causés par le tir des armes lors des tests manuels. Ensuite, nous nous sommes demandé: combien de bogues avons-nous encore et combien peuvent apparaître lors de la refactorisation?

Comme nous ne voulions pas réduire le nombre de tests, mais plutôt l'augmenter, puisque nous avions prévu des mises à jour majeures et une augmentation du nombre de contenus, nous ne voulions pas croître horizontalement et augmenter le nombre d'employés AQ. Au lieu de cela, nous avons planifié une croissance verticale avec une réduction de la routine des employés actuels et une simplification de leur vie lors des tests d'intégration de nouveaux contenus.




Quels outils utilisons-nous


Lorsque nous avons commencé à automatiser les tests, nous avons tout d'abord attiré l'attention sur les outils de test d'intégration Unity, qui étaient intégrés à l'époque à Unity à l'époque. Nous y avons écrit plusieurs interfaces utilisateur et tests de base, terminé le refactoring que nous avons commencé plus tôt, et nous en sommes satisfaits, car la solution fonctionnait déjà, ce qui signifie que nos hypothèses étaient correctes, et nous avons dû passer à autre chose. Le seul point négatif de cette solution, mais très significatif pour nous, était que les tests ne pouvaient pas être exécutés sur des appareils mobiles.

Ainsi, nous avons eu l'idée d'utiliser le framework Appium. Ceci est une fourchette d'un autre cadre de test bien connu - Selenium. À son tour, c'est peut-être le cadre le plus célèbre pour tester des applications Web, dont le concept principal est de travailler avec des éléments d'interface utilisateur, d'obtenir leurs coordonnées et d'organiser les entrées dans ces éléments d'interface utilisateur. Appium a adopté ce concept et, en plus des pilotes Web existants dans Selenium, a également ajouté des pilotes iOS et Android: ils utilisent des cadres de test natifs pour chacune de ces plates-formes.

Puisqu'il n'y a pas d'éléments d'interface utilisateur natifs dans Unity, et qu'il n'y a qu'un seul élément d'interface utilisateur dans lequel l'image est rendue, j'ai dû ajouter en plus d'Appium UnityDriver, qui vous permet de travailler avec la hiérarchie de scène, d'obtenir des objets de scène, et bien plus encore.

À ce moment-là, un ingénieur QA était déjà apparu sur le projet, les choses ont commencé à couler, le nombre de scénarios de test a commencé à augmenter de manière significative, que nous avons progressivement automatisé. Nous avons commencé à les lancer sur des appareils, et en général, notre travail a déjà cherché la façon dont nous voulions.

À l'avenir, en plus des tests d'interface utilisateur, des tests de base et d'autres outils basés sur notre système ont commencé à apparaître, à la suite de quoi nous avons rencontré des performances et une qualité de travail sur divers appareils, ajouté la prise en charge de plusieurs autres appareils, des tests parallèles et abandonné Appium dans bénéficier de votre propre framework.



Le seul problème qui est resté avec nous - et est toujours - était la hiérarchie de l'interface utilisateur. Parce que si une hiérarchie change dans une scène en raison d'un refactoring de l'interface utilisateur ou d'un travail sur la scène, cela doit être pris en charge dans les tests.

Après les prochaines innovations et révisions, l'architecture de l'ensemble du système a commencé à se présenter comme suit.



Nous prenons la construction War Robots, prenons nos tests, qui sont dans un référentiel séparé, ajoutons des paramètres à exécuter là-bas qui nous permettent de configurer le lancement des tests dans chaque cas, et de tout envoyer à l'agent TeamCity sur un PC distant. L'agent TeamCity lance nos tests, leur transmet les paramètres de construction et de lancement du robot, après quoi les tests commencent à fonctionner et à «communiquer» indépendamment avec les appareils connectés à l'agent TeamCity par fil: mettez des builds dessus, exécutez-les, exécutez certains scripts, supprimez versions, redémarrez l'application et ainsi de suite.

Étant donné que les tests et l'application elle-même s'exécutent sur des appareils physiquement différents - sur un téléphone mobile et un Mac mini - nous devions mettre en œuvre la communication entre notre framework, l'API War Robots et l'API Unity. Nous avons ajouté un petit serveur UDP à l'application, qui reçoit les commandes du framework et communique avec l'API de l'application et Unity via des gestionnaires.



La tâche principale de notre framework est d'organiser le travail des tests: la préparation correcte, l'achèvement et la gestion des appareils. En particulier, la parallélisation pour accélérer le travail, le bon choix d'appareils et de captures d'écran, la communication avec la build. Après avoir terminé les tests, notre framework doit enregistrer tous les artefacts générés et générer un rapport.


Conseils pour choisir les appareils


Séparément, je veux faire attention au choix des appareils à tester.

Une attention considérable devrait être accordée aux hubs. Si vous souhaitez exécuter des tests de performances sur vos appareils - en particulier s'il s'agit d'appareils Android - ils seront à court de puissance. Les concentrateurs doivent fournir l'alimentation nécessaire aux appareils utilisés. Il existe une autre caractéristique très subtile: certains concentrateurs ont une puissance active, et cette alimentation s'éteint après des surtensions, après quoi elle est activée uniquement en appuyant physiquement sur un bouton. Nous avons de tels hubs, ce qui est très gênant.

Si vous souhaitez exécuter des tests d'interface de régression et tester la logique sur des appareils, ne prenez pas d'autres appareils. Prenez les mêmes appareils - mieux les plus productifs que vous pouvez vous permettre, car de cette façon, vous économiserez du temps sur les freins des appareils, la commodité de travailler avec eux et le comportement de l'application sur tous les appareils seront les mêmes.

Un autre problème est l'utilisation des fermes de cloud. Nous ne les utilisons pas encore, bien que nous ayons fait des recherches sur eux: ce qu'ils sont, combien ils coûtent et comment exécuter nos tests sur eux - mais jusqu'à présent, nous avons suffisamment de notre parc d'appareils interne pour couvrir nos demandes.


Rapports de test


Une fois les tests terminés, nous générons un rapport d'allure, qui comprend tous les artefacts créés lors de notre test.

Le principal «cheval de bataille» pour analyser ce qui s'est passé et identifier les causes de l'accident pendant le test est les journaux. Tout d'abord, nous les collectons à partir de notre framework, qui nous renseigne sur l'état du script et sur ce qui s'est passé dans ce script. Nous divisons les journaux dans le système (plus détaillé) et le journal pour QA (plus compact et pratique pour l'analyse). Nous collectons également les journaux système des appareils (par exemple, logcat) et les journaux d'une application Unity.

Pendant la chute des tests, nous prenons également une capture d'écran pour comprendre ce qui se passait sur les appareils au moment de la chute, enregistrer une vidéo pour comprendre ce qui s'est passé avant le crash, et essayer de collecter des informations sur l'état de l'appareil, telles que nos pings de serveur et les informations ifconfig, au maximum pour savoir si l'appareil a une IP. Vous serez surpris, cependant, si vous lancez l'application manuellement 50 fois, tout ira bien, mais si vous l'exécutez 50000 fois en mode automatique, vous constaterez que l'Internet sur l'appareil peut être perdu, et ce ne sera pas clair pendant le test, s'il y avait une connexion avant et après la chute.

Nous collectons également une liste des processus, la puissance de la batterie, la température et généralement tout ce que nous pouvons atteindre.




Quelles sont les bonnes captures d'écran et vidéos


Il y a quelque temps, notre ingénieur QA a suggéré, en plus de prendre des captures d'écran à l'automne, à certains endroits des tests de comparer ces captures d'écran avec les modèles qui se trouvent dans notre référentiel. Ainsi, il a proposé de gagner du temps sur le nombre d'exécutions de test et de réduire la taille de la base de code. Autrement dit, avec un test, nous pourrions vérifier la logique et la partie visuelle. Du point de vue du concept de tests unitaires, ce n'est pas très correct, car dans un test, nous ne devons pas tester plusieurs hypothèses. Mais c'est une étape délibérée: nous savons analyser tout cela correctement, nous nous sommes donc aventurés à ajouter des fonctionnalités similaires.

Tout d'abord, nous avons pensé à ajouter des bibliothèques pour faire correspondre les captures d'écran, mais nous avons réalisé que l'utilisation d'images avec des résolutions différentes n'est pas très fiable, nous nous sommes donc arrêtés sur des appareils avec la même résolution et comparons simplement les images avec un certain seuil pixel par pixel.



Un effet très intéressant de l'utilisation de la correspondance des captures d'écran est que si certains processus sont difficiles à automatiser, nous les automatiserons dans la mesure du possible, puis nous examinerons simplement les captures d'écran manuellement. C'est exactement ce que nous avons fait avec la localisation des tests. Nous avons reçu une demande pour tester la localisation de nos applications, alors nous avons commencé à chercher des bibliothèques qui permettent la reconnaissance de texte - mais nous nous sommes rendu compte que c'était plutôt peu fiable, et en conséquence, nous avons écrit plusieurs scripts qui «marchent» sur différents écrans et provoquent des pop-ups différents. ups, et à ce moment des captures d'écran sont créées. Avant de démarrer un tel script, nous modifions les paramètres régionaux sur l'appareil, exécutons le script, prenons des captures d'écran, modifions à nouveau les paramètres régionaux et réexécutons le script. Ainsi, tous les tests sont exécutés la nuit,afin que le matin, l'ingénieur QA puisse regarder 500 captures d'écran et analyser immédiatement s'il y a des problèmes de localisation quelque part. Oui, les captures d'écran doivent encore être regardées, mais cela est beaucoup plus rapide que de passer manuellement à travers tous les écrans de l'appareil.

Parfois, les captures d'écran et les journaux ne suffisent pas: quelque chose d'étrange commence à se produire sur les appareils, mais comme ils sont situés à distance, vous ne pouvez pas aller évaluer ce qui s'y est passé. De plus, il est parfois difficile de savoir ce qui s'est passé littéralement quelques instants avant la chute du test. Par conséquent, nous avons ajouté un enregistrement vidéo de l'appareil, qui commence au début du test et n'est sauvegardé qu'en cas de chute. Avec l'aide de telles vidéos, il est très pratique de suivre les plantages et les blocages d'applications.




Que peut faire d'autre notre système?


Il y a quelque temps, du département de test de QA, nous avons reçu une demande pour développer un outil de collecte de métriques lors de tests manuels.

Pourquoi est-ce?

Cela est nécessaire pour que les ingénieurs QA, après un test de lecture manuel, puissent en outre analyser le comportement du FPS et la consommation de mémoire dans l'application, en regardant simultanément des captures d'écran et des vidéos reflétant ce qui se passait sur cet appareil.

Le système développé par nous a fonctionné comme suit. L'ingénieur QA a lancé War Robots sur l'appareil, a activé l'enregistrement de la session playbench - notre analogue du gamebench - a joué le playtest, puis a cliqué sur "mettre fin à la session playbench", le rapport généré a été enregistré dans le référentiel, après quoi l'ingénieur avec les données pour ce playtest pourrait atteindre son travail machines et voir le rapport: quels étaient les rabattements sur FPS, quelle consommation de mémoire, ce qui se passait sur l'appareil.

Nous avons également automatisé le lancement de repères sur le projet War Robots, en regroupant essentiellement les repères existants dans un lancement automatique. Le résultat des repères est généralement à un chiffre. Dans notre cas, il s'agit généralement du FPS moyen par référence. En plus du lancement automatique, nous avons décidé d'ajouter une autre session de playbench et avons ainsi reçu non seulement un chiffre spécifique, le fonctionnement du benchmark, mais aussi des informations grâce auxquelles nous pouvons analyser ce qui est arrivé au benchmark à ce moment.

Il faut également mentionner le test de demande de pull. Cette fois, c'était plus pour aider l'équipe de développement client que les ingénieurs QA. Nous exécutons le test de vérification de construction pour chaque demande de tirage. Vous pouvez les exécuter à la fois sur les appareils et dans l'éditeur Unity pour accélérer le travail de vérification de la logique. Nous exécutons également un ensemble de core-tests dans des branches distinctes, où une sorte de refonte de certains éléments ou de refactorisation de code a lieu.




Et d'autres fonctionnalités utiles


En fin de compte, je veux m'attarder sur certains cas intéressants que nous avons rencontrés au cours des dernières années.

L'un des cas les plus intéressants qui sont apparus récemment avec nous est celui des références lors des combats avec des bots.

Pour le nouveau projet, Pixonic Dino Squad a développé un système dans lequel l'ingénieur QA pourrait jouer un test de jeu avec des bots, afin de ne pas attendre ses collègues, mais de tester une hypothèse. Notre ingénieur QA, à son tour, a demandé d'ajouter la possibilité non seulement de jouer avec les bots, mais aussi pour que les bots puissent jouer les uns avec les autres. Ainsi, nous lançons simplement l'application, et à ce moment le bot commence à jouer avec d'autres bots. En même temps, toute l'interaction est en réseau, avec de vrais serveurs, juste au lieu de joueurs jouant sur un ordinateur. Tout cela est emballé dans des repères et une session de playbench avec des déclencheurs pour les démarrages nocturnes. Ainsi, la nuit, nous commençons plusieurs batailles entre les bots et les bots, à ce moment, les FPS et la consommation de mémoire sont écrits, des captures d'écran sont prises et des vidéos sont enregistrées. Le matin, un ingénieur QA vient et peut voir,quels tests ont été organisés et ce qui s'est passé sur eux.

La fuite de texture mérite également d'être vérifiée. Il s'agit d'une sorte de sous-analyse de l'utilisation de la mémoire - mais ici, nous vérifions principalement l'utilisation, par exemple, des textures de garage au combat. Par conséquent, dans la bataille, il ne devrait pas y avoir d'atlas utilisés dans le garage, et lorsque nous quittons la bataille, les textures qui ont été utilisées dans la bataille ne doivent pas rester en mémoire.

Un effet secondaire intéressant de notre système est que presque depuis le tout début de son utilisation, nous avons suivi le temps de chargement de l'application. Dans le cas des robots de guerre, cette fois n'est pas forte, mais elle est en constante augmentation, car de nouveaux contenus sont ajoutés et la qualité de ce contenu s'améliore - mais nous pouvons garder ce paramètre sous contrôle et toujours être conscient de sa taille.


Au lieu d'une conclusion


En fin de compte, je voudrais attirer l'attention sur les problèmes que nous connaissons et que nous aimerions résoudre en premier lieu.



Le premier et le plus douloureux concerne les modifications de l'interface utilisateur. Puisque nous travaillons avec une boîte noire, nous n'intégrons rien dans l'application War Robots à l'exception de notre serveur - c'est-à-dire que nous testons tout de la même manière qu'un ingénieur QA le ferait. Mais d'une manière ou d'une autre, nous devons accéder aux éléments de la scène. Et nous les trouvons le long du chemin absolu. Ainsi, lorsque quelque chose change sur la scène, en particulier à un haut niveau de hiérarchie, nous devons accompagner ces changements dans un grand nombre de tests. Malheureusement, nous ne pouvons rien faire pour le moment. Bien sûr, il existe des solutions, mais elles apportent leurs problèmes supplémentaires.

Le deuxième gros problème est l’infrastructure. Comme je l'ai dit, si vous exécutez votre application 50 fois avec vos mains, vous ne remarquerez pas la plupart des problèmes qui apparaîtront si vous exécutez votre application 50 000 fois. Ces problèmes qui peuvent être facilement résolus en mode manuel - par exemple, la réinstallation de builds ou le redémarrage d'Internet - se révéleront être une véritable douleur dans l'automatisation, car tous ces problèmes doivent être correctement gérés, un message d'erreur affiché et à condition qu'ils puissent se produire du tout. En particulier, nous devons déterminer pourquoi les tests ont échoué: en raison d'une logique défectueuse ou d'une sorte de problème d'infrastructure, ou pour toute autre raison. Il y a beaucoup de problèmes avec les appareils bas de gamme: ils n'ont pas de builds, Internet tombe en panne, les appareils gèlent, tombent en panne, ne s'allument pas, sont rapidement déchargés, etc.

Je voudrais également interagir avec des interfaces utilisateur natives, mais jusqu'à présent, nous n'avons pas une telle opportunité. Nous savons comment procéder, mais la présence d'autres demandes de fonctionnalités ne nous permet pas d'y parvenir.

Et personnellement, mon désir est de respecter les normes qui existent dans l'industrie, mais c'est aussi dans les plans pour l'avenir, peut-être même cette année.

All Articles