A la fin du précédent article, nous en étions restés à une application GWT testée unitairement :
Ces tests sont exécutés avec JUnit ou Maven, comme n'importe quel autre test. Nous sommes donc capables de lancer l'application GWT dans une JVM standard. Rien ne s'affiche, mais toutes les classes sont instanciées, et les comportements sont implémentés. Par contre la partie serveur (qui reçoit les appels GWT-RPC) est mockée.
La faiblesse de ces tests est qu'ils sont unitaires : on teste le comportement d'un écran. Or les problèmes commencent lors que l'on enchaine les écrans...
Dans notre cas, la partie serveur est faite avec Spring. Nous la testons donc avec le SpringJUnit4ClassRunner
, qui nous démarre tout la partie serveur dans JUnit. En ajoutant un peu de glue, nous avons donc "bouclé la boucle" : au lieu de mocker la partie serveur de l'appli GWT, nous avons branché la partie IHM sur la partie serveur en Spring :
L'application GWT et son serveur sont donc complètement démarrés et opérationnels dans une JVM pour faire des tests.
Ce ne sont plus des tests unitaires, ce sont de véritables tests d'intégrations.
Aucune modification coté serveur n'a été nécessaire. Nous avons juste ajouté un peu de glue pour brancher l'application GWT sur la partie Spring. Avant, nous avions déjà des tests d'intégrations qui mockaient la partie "sous" le serveur : bases de données, WebServices... Nous avons juste réutilisé cet environnement.
Pour stimuler l'application GWT, on peut faire du Java. Par exemple :
MyView myView = (MyView) RootPanel.get(0);
myView.getButton().click();
Ce n'est pas très pratique, il faut mettre des getters partout. En plus, on va souvent vouloir aller chercher la 4ème checkbox située dans la table X elle-même située dans le conteneur Y lui-même situé dans le RootPanel. C'est pourquoi nous avons développé un petit langage ressemblant à XPath permettant d'aller chercher des composants et d'appeler des méthodes dessus. Par exemple, pour s'assurer qu'un label situé dans le premier widget d'un conteneur, lui même dans le troisième widget du RootPanel, cela donne :
/rootPanel/widget(2)/widget(0)
Son texte, accessible normalement par getText()
est accessible par
/rootPanel/widget(2)/widget(0)/text
Tout cela en utilisant lourdement l'introspection Java.
Nos scenarii de tests sont donc écrit à base de ces XPath, en CSV. Voici un exemple de scénario CSV qui :
Voila le scénario
initApp;
assertExact;toto;/rootPanel/widget(2)/widget(0)/text
click;/rootPanel/widget(2)/widget(1)
assertExact;titi;/rootPanel/widget(2)/widget(0)/text
Un peu de code permet de lancer ce scénario dans JUnit. On l'exécute donc de la même façon que les tests unitaires, ils sont juste plus long (à cause du démarrage de la partie serveur).
La partie test d'intégration est aussi dans le projet gwt-test-utils. La documentation est ici.
On aurait pu faire a peu près la même chose avec Sélénium. Il y a deux grosses différences :
Dans le cadre de notre projet, nous avons écrit 40 scenarii en CSV. Certains sont assez long (200 lignes). Ces 40 scenarii nous assurent une non régression totale sur l'ensemble des fonctionnalités de notre application !
GWT s'avère une technologie IHM qui, via quelques outils, permet de faire des tests de manière extrêmement poussé. Ce qui augmente encore la productivité de cette technologie !