Comment puis-je tester unitaire une interface graphique?

155

Les calculs de mon code sont bien testés, mais comme il y a tellement de code GUI, ma couverture globale du code est inférieure à ce que je souhaiterais. Existe-t-il des directives sur le code GUI de test unitaire? Cela a-t-il même un sens?

Par exemple, il y a des graphiques dans mon application. Je n'ai pas été en mesure d'automatiser le test des graphiques. Il faut un œil humain, AFAIK, pour vérifier si le graphique est correct.

(J'utilise Java Swing)

Steve McLeod
la source
1
Il existe un excellent article sur les différentes architectures GUI de Martin Fowler ( martinfowler.com/eaaDev/uiArchs.html ). Il décrit les compromis d'architecture GUI en termes de tests unitaires.
Roman Hwang
1
De nos jours, cette question serait mieux posée sur programmers.stackexchange.com (et est probablement hors sujet sur Stack Overflow, au motif qu'elle est trop large), mais les anciennes questions ne peuvent pas être migrées. La question de savoir s'il appartient ici à part, le problème reste intéressant et difficile.
Mark Amery
1
Ce serait génial d'avoir un exemple avec un morceau de code GUI et JUnit.
Witold Kaczurba
1
Je dirais simplement détendez-vous et ne vous inquiétez pas. L'effort consacré aux tests unitaires ne s'avère pas toujours productif.
codeulike le
Ancienne question encore, vous pouvez tester le flux dans l'interface graphique en utilisant Jubula
Abi

Réponses:

68

Les conceptions comme MVP et MVC essaient généralement d'abstraire autant de logique que possible de l'interface graphique réelle. Un article très populaire à ce sujet est "The Humble Dialog Box" de Michael Feathers. Personnellement, j'ai eu des expériences mitigées en essayant de déplacer la logique hors de l'interface utilisateur - parfois cela fonctionnait très bien, et à d'autres moments, cela posait plus de problèmes que cela ne valait la peine. Cela dépasse cependant un peu mon domaine d'expertise.

Jon Skeet
la source
??? "parfois ça a très bien fonctionné, et à d'autres moments ça a été plus de problèmes que ça en vaut la peine" Très bizarre parce que la plupart des nouveaux langages ont tendance à être orientés MVC ... ce qui est logique hors de l'interface graphique (Model-Visual) ...
Patrick Desjardins
14
Pourtant, la logique de présentation sera dans l'interface graphique. Parfois, cela peut être loin d'être anodin
Andrea
16
Mirror: The Humble Dialog Box
c24w
Traitement du concept par Martin Fowler (dans le cas où votre réseau, comme le mien, filtre archive.org): martinfowler.com/eaaDev/uiArchs.html#HumbleView
Christopher Berman
@ c24w merci d'avoir tiré ce miroir, vous êtes le vrai MVP :)
John Baker
38

Bien sûr, la réponse est d'utiliser MVC et de déplacer autant de logique que possible hors de l'interface graphique.

Cela étant dit, j'ai entendu dire par un collègue il y a longtemps que lorsque SGI portait OpenGL sur un nouveau matériel, ils avaient un tas de tests unitaires qui dessinaient un ensemble de primatives à l'écran, puis calculaient une somme MD5 du tampon de trame. Cette valeur pourrait ensuite être comparée à de bonnes valeurs de hachage connues pour déterminer rapidement si l'API est précise par pixel.

dicroce
la source
3
J'aime cette approche. Difficile à configurer et à maintenir, mais cela me donnerait les capacités de test de régression dont j'ai besoin.
Steve McLeod
7
danatel vous avez manqué le point. OpenGL est une API de rendu graphique au pixel près. Les frameworks d'applications GUI comme Qt vont être fortement dépendants du chrome système, donc hacher le frame buffer n'est pas une bonne approche.
Bob Somers
1
Un MD5? Qu'est-ce qu'un hachage cryptographique a à voir avec cela? Comment la sécurité est-elle impliquée? Un hachage, OK, c'est une excellente idée pour des graphismes au pixel près mais un hachage cryptographique? Vous pouvez utiliser des hachages plus rapides qui ne sont pas cryptographiques et dont la probabilité de collision est négligeable. Êtes-vous sûr que c'était un hachage cryptographique et pas simplement un hachage? (en plus de cela, à l'heure actuelle du calcul parallèle, l'algorithme de hachage [utilisé à des fins non cryptographiques] qui ne peut pas être parallélisé doit être considéré avec suspicion)
SyntaxeT3rr0r
24
@ SyntaxT3rr0r: Quelle fonction de hachage recommanderiez-vous dans ce type d'application non liée à la sécurité, et à quel niveau de gain de performances peut-on s'attendre par rapport à MD5?
Lèse majesté
1
Votre réponse signifie "ne jamais concevoir votre interface graphique et donc ne pas la tester". Cool.
Dim
10

Vous pouvez essayer UISpec4J est une bibliothèque de tests fonctionnels et / ou unitaires Open Source pour les applications Java basées sur Swing ...

CMS
la source
2
J'ai commencé à utiliser UISpec4J pendant environ un mois pour faire des tests de validation des exigences sur l'interface graphique Java Swing. Je l'ai beaucoup aimé jusqu'à présent.
Bassam
github.com/UISpec4J/UISpec4J indique que votre lien est le site officiel, mais il ne me semble pas aussi officiel. Tout ce que je vois est un blog sur le vlogging
lucidbrot
7

Il existe Selenium RC , qui automatisera les tests d'une interface utilisateur Web. Il enregistrera les actions et les rejouera. Vous aurez toujours besoin de parcourir les interactions avec votre interface utilisateur, donc cela n'aidera pas à la couverture, mais cela peut être utilisé pour les builds automatisés.

David Robbins
la source
7

Vous pouvez essayer d'utiliser Cucumber et Swinger pour écrire des tests d'acceptation fonctionnelle en anglais clair pour les applications Swing GUI. Swinger utilise la bibliothèque Jemmy de Netbeans sous le capot pour piloter l'application.

Le concombre vous permet d'écrire des tests comme celui-ci:

 Scenario: Dialog manipulation
    Given the frame "SwingSet" is visible
    When I click the menu "File/About"
    Then I should see the dialog "About Swing!"
    When I click the button "OK"
    Then I should not see the dialog "About Swing!"

Jetez un œil à cette démo vidéo Swinger pour la voir en action.

Dema
la source
6

Voici quelques conseils:

Essayez de supprimer le plus de code possible de l'interface graphique (avoir un contrôleur et un objet modèle) de cette façon, vous pourrez les tester sans l'interface graphique.

Pour le graphique, vous devez tester la valeur que vous fournissez au code qui génère le graphique.

Patrick Desjardins
la source
6

Le test est une forme d'art. Je suis d'accord que la logique devrait être supprimée autant que possible de l'interface graphique. Nous pouvons alors y concentrer nos tests unitaires. Comme toute autre chose, les tests visent à réduire les risques. Vous n'avez pas toujours besoin de tout tester, mais souvent, la meilleure chose est de briser les différents tests dans différents domaines.

L'autre question est de savoir ce que vous essayez vraiment de tester au niveau de l'interface utilisateur. Les tests d'interface utilisateur sont les tests les plus coûteux, car ils prennent généralement plus de temps à créer, à maintenir et ils sont les plus fragiles. Si vous testez la logique pour savoir que les coordonnées sont correctes avant d'essayer de tracer la ligne, que testez-vous spécifiquement? Si vous souhaitez tester un graphique avec une ligne rouge est dessinée. Pouvez-vous lui donner un ensemble de coordonnées prédéterminées et tester si certains pixels sont rouges ou non rouges? Comme suggéré ci-dessus, les comparaisons bitmap fonctionnent, Selenium, mais mon objectif principal serait de ne pas sur-tester l'interface graphique, mais plutôt de tester la logique qui aidera à créer l'interface utilisateur, puis de se concentrer sur la partie de l'interface utilisateur qui se brise ou est suspecte et de concentrer une poignée de tests Là.

Charles Smith
la source
3

Vous pouvez utiliser JFCUnit pour tester votre interface graphique, mais les graphiques peuvent être plus difficiles. J'ai pris à plusieurs reprises des instantanés de mon interface graphique et l'ai automatiquement comparée à une version précédente. Bien que cela ne fournisse pas de test réel, il vous alerte si une génération automatique ne parvient pas à produire la sortie attendue.

Steve Moyer
la source
3

Ce que je déduis de votre question, c'est que vous recherchez un moyen automatisé de tester en détail le comportement de votre interface graphique, l'exemple que vous donnez est de tester si une courbe est réellement dessinée correctement.

Les frameworks de tests unitaires fournissent un moyen de faire des tests automatisés, mais je pense que le type de tests que vous voulez faire sont des tests d'intégration compliqués qui vérifient le comportement correct d'une multitude de classes, parmi lesquelles les classes de votre boîte à outils / bibliothèque GUI, que vous ne devrait pas vouloir tester.

Vos options dépendent beaucoup des plates-formes / boîtes à outils / frameworks que vous utilisez: par exemple, une application utilisant Qt comme framework GUI peut utiliser Squish pour automatiser ses tests. Vous vérifiez les résultats de vos tests une fois, et les tests exécutés automatiquement par la suite comparent les résultats aux résultats vérifiés.

andreas buykx
la source
2

Mon approche des tests GUI évolue, tout comme le consensus de l'industrie. Mais je pense que quelques techniques clés commencent à émerger.

J'utilise une ou plusieurs de ces techniques, en fonction de la situation (par exemple de quel type d'interface graphique il s'agit, à quelle vitesse elle doit être construite, qui sera l'utilisateur final, etc.).

  1. Test manuel. L'interface utilisateur graphique est toujours en cours d'exécution lorsque vous travaillez sur le code et assurez-vous qu'elle est synchronisée avec le code. Vous testez et retestez manuellement la partie sur laquelle vous travaillez pendant que vous travaillez dessus, en basculant entre le code et l'application en cours d'exécution. Chaque fois que vous effectuez un travail important, vous testez l'ensemble de l'écran ou de la zone de l'application pour vous assurer qu'il n'y a pas de régressions.

  2. Tests unitaires.Vous écrivez des tests pour des fonctions ou de petites unités de comportement GUI. Par exemple, vos graphiques peuvent avoir besoin de calculer différentes nuances d'une couleur en fonction d'une couleur «de base». Vous pouvez extraire ce calcul dans une fonction et y écrire un test unitaire. Vous pouvez rechercher une logique comme celle-ci dans l'interface graphique (en particulier la logique réutilisable) et l'extraire en fonctions discrètes, qui peuvent être plus facilement testées à l'unité. Même un comportement complexe peut être extrait et testé de cette manière - par exemple, une séquence d'étapes dans un assistant peut être extraite vers une fonction et un test unitaire peut vérifier que, étant donné une entrée, l'étape correcte est renvoyée.

  3. Explorateur de composants.Vous créez un écran «explorateur» dont le seul rôle est de présenter chacun des composants réutilisables qui composent votre interface graphique. Cet écran vous offre un moyen rapide et facile de vérifier visuellement que chaque composant a le bon aspect et la bonne sensation. L'explorateur de composants est plus efficace que de parcourir manuellement l'ensemble de votre application, car A) vous n'avez à vérifier chaque composant qu'une seule fois, et B) vous n'avez pas à naviguer profondément dans l'application pour voir le composant, vous pouvez simplement afficher et vérifiez-le immédiatement.

  4. Test d'automatisation. Vous écrivez un test qui interagit avec l'écran ou le composant, simulant des clics de souris, la saisie de données, etc., affirmant que l'application fonctionne correctement compte tenu de ces manipulations. Cela peut être utile comme test de sauvegarde supplémentaire, pour capturer les bogues potentiels que vos autres tests pourraient manquer. J'ai tendance à réserver les tests d'automatisation aux parties de l'interface graphique qui sont les plus susceptibles de se casser et / ou qui sont très critiques. Parties où je veux savoir le plus tôt possible si quelque chose s'est cassé. Cela peut inclure des composants interactifs très complexes qui sont vulnérables aux pannes ou aux écrans principaux importants.

  5. Test de Diff / Snapshot. Vous écrivez un test qui capture simplement la sortie sous forme de capture d'écran ou de code HTML et la compare avec la sortie précédente. De cette façon, vous êtes alerté chaque fois que la sortie change. Les tests de différences peuvent être utiles si l'aspect visuel de votre GUI est complexe et / ou sujet à changement, auquel cas vous voulez un retour rapide et visuel sur l'impact d'un changement donné sur l'interface graphique dans son ensemble.

Plutôt que d'utiliser massivement tous les types de tests possibles, je préfère choisir la technique de test en fonction du type de chose sur laquelle je travaille. Dans un cas, je vais donc extraire une fonction simple et la tester unitaire, mais dans un autre cas, j'ajouterai un composant à l'explorateur de composants, etc. Cela dépend de la situation.

Je n'ai pas trouvé que la couverture de code était une métrique très utile, mais d'autres peuvent en avoir trouvé une utilisation.

Je pense que la première mesure est le nombre et la gravité des bogues. Votre première priorité est probablement d'avoir une application qui fonctionne correctement. Si l'application fonctionne correctement, il devrait y avoir peu ou pas de bogues. S'il y a des bogues nombreux ou graves, alors probablement, vous ne testez pas ou vos tests ne sont pas efficaces.

Outre la réduction des bogues, il existe d'autres mesures telles que les performances, la convivialité, l'accessibilité, la maintenabilité, l'extensibilité, etc. Celles-ci varieront en fonction du type d'application que vous créez, de l'entreprise, de l'utilisateur final, etc.

Tout cela est basé sur mon expérience et mes recherches personnelles, ainsi que sur un excellent article sur les tests d'interface utilisateur par Ham Vocke .

Jonathan
la source
1

D'après ce que je sais, c'est assez compliqué et dépend vraiment de la langue - de nombreux langages ont leur propre façon de tester l'interface graphique, mais si vous avez vraiment besoin de tester l'interface graphique (par opposition à l'interaction modèle / interface graphique), vous devez souvent simuler un utilisateur réel en cliquant sur les boutons. Par exemple, le framework SWT utilisé dans Eclipse fournit SWTBot , JFCUnit a déjà été mentionné, Mozilla a sa propre façon de simuler cela dans XUL (et d'après ce que j'ai lu sur leurs blogs, ces tests semblent assez fragiles).

Parfois, vous devez prendre une capture d'écran et tester le rendu au pixel près (je crois que Mozilla fait cela pour vérifier les pages correctement rendues) - cela nécessite une configuration plus longue, mais peut-être ce dont vous avez besoin pour les graphiques. De cette façon, lorsque vous mettez à jour votre code et qu'un test est interrompu, vous devez vérifier manuellement l'image si l'échec était réel, ou vous avez amélioré le code de rendu des graphiques pour générer des graphiques plus jolis et vous devez mettre à jour les captures d'écran.

Kim Sullivan
la source
0

Si vous utilisez Swing, FEST-Swing est utile pour piloter votre GUI et tester les assertions. Il est assez simple de tester des choses comme "si je clique sur le bouton A, la boîte de dialogue B doit être affichée" ou "si je sélectionne l'option 2 dans la liste déroulante, toutes les cases à cocher doivent être désélectionnées" .

Le scénario graphique que vous mentionnez n'est pas si facile à tester. Il est assez facile d'obtenir une couverture de code pour les composants GUI simplement en les créant et en les affichant (et peut-être en les pilotant avec FEST). Cependant, faire des assertions significatives est la partie difficile (et la couverture de code sans assertions significatives est un exercice d'auto-tromperie). Comment testez-vous que le graphique n'a pas été dessiné à l'envers ou trop petit?

Je pense que vous devez simplement accepter que certains aspects des interfaces graphiques ne peuvent pas être testés efficacement par des tests unitaires automatisés et que vous devrez les tester d'une autre manière.

Dan Dyer
la source
0

Ce n'est pas votre travail de tester la bibliothèque GUI. Ainsi, vous pouvez éviter la responsabilité de vérifier ce qui est réellement dessiné à l'écran et vérifier les propriétés des widgets à la place, en faisant confiance à la bibliothèque pour qu'ils représentent avec précision ce qui est dessiné.

ivan_pozdeev
la source