Quel est le moyen recommandé pour unittest applications GUI Python?

Je suis actuellement assez stupide pour essayer de maintenir deux bases de code parallèles pour une application de bureau Python, l'Une utilisant L'introspection PyGObject pour GTK 3 et L'autre utilisant PyGTK pour GTK 2. Je travaille principalement sur la branche PyGObject, puis je porte les changements sur la branche PyGTK. En raison de toutes les différences mineures entre ces implémentations, je néglige souvent les choses et provoque des bris que je rate et libère accidentellement, seulement pour être attrapé par les utilisateurs.

J'essaie de comprendre un bon moyen de concevoir des tests unitaires qui, de préférence, conviendraient à fonctionner sur les deux bases de code. Ce n'est pas un programme trop compliqué, (c'est essentiellement un outil de gestion de bibliothèque, imaginez comme iTunes):

- Main Window
  |- Toolbar with some buttons (add/edit/remove items, configure the program)
  |
  |- VPaned
  |--- Top HPaned
  |------ ListView (listing values by which a library of items can be filtered)
  |------ ListView (listing the contents of the library
  |--- Bottom HPaned
  |------ Image (displaying cover art for the currently selected item in the library)
  |------ TextView (displaying formatted text describing the currently selected item)
 - Edit dialog
 - Configuration dialog
 - About dialog 

J'ai essayé de séparer les vues des modèles autant que possible. Chacun de ces éléments est implémenté dans sa propre classe (enfin, dans les classes qui héritent des classes GTK listées). Les ListViews sont couplés avec d'autres classes qui héritent de ListStores. La bibliothèque elle-même est géré par une classe différente. Néanmoins, il y a des interactions entre les widgets qui doivent être testés. Par exemple, si l'utilisateur sélectionne un élément particulier dans la vue filtre, en filtrant la bibliothèque, puis en sélectionnant un élément à partir des résultats filtrés, la vue texte doit afficher les informations pour l'entrée de bibliothèque correcte, ce qui est semi-compliqué en raison de la traduction d'iters entre TreeModelFilter et le ListStore d'origine, etc.

Donc, je demande, Quelle est la manière recommandée pour écrire des tests unitaires robustes pour une telle application GUI? J'ai vu qu'il y a quelques bibliothèques pour cela, mais les principales pour pygtk n'ont pas été mises à jour depuis des années et elles échoueront certainement avec L'introspection PyGObject. Peut-être que je ne suis pas assez créatif pour trouver un bon moyen de le faire en utilisant le module unittest de Python, donc je suis ouvert aux suggestions.

36
demandé sur Jürgen Strobel 2011-08-26 19:09:25

4 réponses

Êtes-vous sûr de vouloir unité tester L'interface graphique? Votre exemple de complexité implique plus de 1 unité et est donc un test d'intégration.

Si vous voulez vraiment tester l'unité, vous devriez pouvoir instancier une seule classe fournissant des mocks ou des stubs pour ses dépendances,puis appeler des méthodes comme le ferait le framework GUI par exemple un clic utilisateur. Cela peut être fastidieux et vous devez savoir exactement comment le framework GUI distribue l'entrée de l'utilisateur à vos classes.

Mon conseil est à mettre encore plus de choses dans les modèles. Pour votre exemple donné, vous pouvez créer un FilterManager qui résume tous les éléments de filtre/sélection/affichage derrière une seule méthode. L'unité de test.

4
répondu Jürgen Strobel 2011-08-31 23:36:51

Il existe un excellent moyen de tester directement les fonctions et les widgets PyGTK, sans passer par des frameworks de test d'acceptation/fonctionnalité/Intégration qui se faufilent dans l'oubli. J'ai appris à ce sujet dans ce post, qui est assez explicite. Mais l'idée de base est que vous traitez vos widgets comme des fonctions / classes, et vous pouvez les tester directement. Si vous avez besoin de traiter les rappels et ainsi de suite, il y a un truc soigné que je vais reproduire ici:

import time
import gtk

# Stolen from Kiwi
def refresh_gui(delay=0):
  while gtk.events_pending():
      gtk.main_iteration_do(block=False)
  time.sleep(delay)

Comme mentionné dans le billet de blog, ce code est LGPL. Sinon, quand vous y réfléchissez, tant que vous n'avez pas show() windows ou widgets, vous pouvez les tester tout ce que vous voulez et ils doivent se comporter comme s'ils étaient réels parce que, d'une certaine manière, ils le sont. Ils sont tout simplement pas affiché.

Bien sûr, vous devez simuler vous-même l'interaction sur les boutons et les widgets interactifs en appelant clicked() sur un bouton par exemple. Voir à nouveau L'excellent post D'Ali Afshar sur les tests unitaires dans PyGTK .

5
répondu anarcat 2014-02-18 01:27:41

En collant avec le thème que Jürgen était correct en ce sens que je ne suis pas intéressé par les testsunit , mais réellement intéressé par les tests d'intégration, j'ai également trouvé ce framework de freedesktop.org: http://ldtp.freedesktop.org/wiki/

Il permet d'automatiser une variété de tests pour les applications GUI compatibles avec L'accessibilité (y compris GTK, Qt, Swing, etc.).

2
répondu 2012-02-26 10:37:27

Vous pouvez utiliser un framebuffer X11:

Xvfb :119 -screen 0 1024x768x16 &
export DISPLAY=:119
... run your tests

Assurez-vous de ne pas entrer gtk.main(), car cela attendrait l'entrée de la souris ou du clavier. Vous pouvez utiliser ce modèle pour laisser gtk gérer tous les événements:

def refresh_gui():
  while gtk.events_pending():
      gtk.main_iteration_do(block=False)

AFAIK vous ne pouvez pas voir votre application, mais vous pouvez tester vos rappels.

0
répondu guettli 2014-05-05 08:57:51