Tester une application web avec FluentLenium

1. Introduction

Tester l’IHM (Interface Homme Machine) d’une application après l’ajout d’une nouvelle fonctionnalité ou la correction d’une anomalie peux prendre beaucoup de temps car il faut de nouveau tester l’affichage et les interactions possibles sur/entre chaque page :

  • Affichage correcte des pages
  • Fonctionnement de tous les liens présents sur chaque page
  • Exécution correcte des scripts JavaScript
  • Cas passants et non passants sur les formulaires (champs obligatoires, règles de gestion….)
  • Etc…

Afin de pouvoir tester l’IHM de vos applications web de façon automatique, plusieurs solutions existent, dont la plus connue est Selenium. Cependant, cette solution n’est pas simple à mettre en œuvre, trop verbeuse et difficilement maintenable.

FluentLenium, développé par Mathilde Lemée permet de palier à ces soucis de complexité tout en garantissant la maintenabilité de votre code en proposant une API simplifiant l’écriture de ces tests Selenium.

Nous allons découvrir au travers de cet article comment l’utiliser dans vos projets.

2. Méthodes proposées par FluentSelenium

2.1 Les sélecteurs

FluentLenium se base sur les sélecteurs CSS1, CSS2 et CSS3 associés à la méthode « find() », par exemple pour récupérer la liste des éléments :

  • Avec l’id « footer » : find(« #footer »)
  • Ayant la classe « foo » : find(« .foo ») ;
  • Tous les champs de type « input » : find(« input »)

2.2 Les filtres

Vous pouvez utiliser des filtres pour affiner votre recherche, exemple :

A noter que vous pouvez vous passer du sélecteur CSS et écrire directement :

Il est également possible d’enchaîner les filtres pour ajouter des critères de restriction :

Il existe d’autres filtres sur les chaînes de caractère :

Comme dans l’exemple précédent vous pouvez ou non utiliser un sélecteur CSS avec ces filtres.

Enfin, si vous êtes plus familier avec la syntaxe Jquery, vous pouvez remplacer la méthode « find() » par « $ » :

2.3 Accéder aux propriétés des éléments sélectionnés

Exemples pour un seul élément :

Exemples pour une liste d’éléments :

2.4 Les formulaires

Remplir le formulaire

Pour remplir votre formulaire, FluentLenium fourni la méthode « fill() » :

Exemple pour remplir tous les champs avec la valeur « foo » :

Vous pouvez également utiliser les sélecteurs CSS ou les filtres vus précédemment :

Actions

Pour simuler un clic sur tous les boutons ayant pour id « myButton » :

Pour effacer tous les champs ayant pour id « myField » :

Pour soumettre votre formulaire :

3. Écriture des tests

3.1 Utilisation du pattern page objet (Page Object Pattern)

Le pattern page objet permet de modéliser l’interface utilisateur (la page web) qui va ensuite être utilisée pour écrire vos tests unitaires.

Les pages vont être vues comme des services que l’on va injecter dans nos différents tests ce qui permet d’avoir un code beaucoup maintenable, réutilisable.

Pour construire un objet de type « page » avec FluentLenium vous devez étendre la classe « org.fluentlenium.core.FluentPage » et définir l’url de la page à tester en surchargeant la méthode « getUrl() ». Vous pourrez ensuite utiliser la méthode goTo(myPage) dans le code de votre test pour accéder à cette page.

Il peut être nécessaire de vérifier si la page sur laquelle vous êtes est vraiment la bonne, pour cela vous devez surcharger la méthode « isAt() » et y renseigner toutes les assertions nécessaires. Par exemple, si le titre de la page suffit pour l’identifier :

Enfin, renseigner dans ces pages toutes les méthodes susceptibles d’être utilisées, il sera ensuite beaucoup plus facile de les utiliser au sein de vos différents tests.

Exemple de page :

Exemple de test associé :

3.2  L’annotation @Page

Vous pouvez facilement injecter une ou plusieurs pages dans votre test unitaire en utilisant l’annotation « @Page », par exemple :

A noter que vous pouvez également injecter une page dans une autre page en utilisant cette même annotation.

 

3.3  Les WebElements

Les WebElements comme leur nom l’indique correspondent à tous les types d’élément HTML (bouton, champs, formulaire, etc…)

Au sein d’une page tous les objets de type FluentWebElement sont par défaut automatiquement recherchés par leur « id » ou leur attribut « name ».

Ainsi, si vous déclarer un bouton « myButton » de type FluentWebElement au sein de votre page, FluentSelenium va automatiquement rechercher au sein de votre interface utilisateur un élément ayant pour id ou pour nom « myButton » :

Mais si l’id ou le nom de vos éléments HTML ne correspondent pas à la convention de nommage de Java, vous pouvez utiliser l’annotation « @FindBy() » afin de récupérer l’élément souhaité par sa classe CSS, son nom etc… :

Vous pouvez également créer vos propres WebElement avec leurs propres méthodes, il suffit pour cela que le constructeur de votre élément prenne en paramètre un objet de type WebElement.
Par exemple, si je souhaite créer un objet de type « MyButton » :

Enfin, si vous devez attendre avant qu’un élément soit disponible, suite à un appel Ajax par exemple, vous pouvez utiliser l’annotation « @AjaxElement »:

Il est possible de spécifier un timeout avant que la page ne propage une erreur si l’élément n’est pas trouvé via la propriété « timeountOnSeconds » (par défaut le timeout est d’une seconde) :

3.4  Appels Ajax

FluentLenium propose une API permettant de gérer efficacement les appels Ajax.
Ainsi, si vous souhaitez attendre au maximum 5 secondes avant que le nombre d’éléments (3 dans cet exemple) correspondant à votre critère de recherche soit affiché :

A noter que par défaut, le temps d’attente avant de propager une erreur est de 500 ms.
Nous venons de voir un exemple avec une vérification sur la taille mais il existe d’autres méthodes :

Vous pouvez ajouter des restrictions en utilisant les filtres et les matchers vus précédemment, exemple :

De la même façon que pour attendre suite à un appel Ajax, vous pouvez placer un timer pour récupérer vos éléments toutes les X (secondes, minutes…), en utilisant la méthode « pollingEvery() »:

3.5  Exécuter du JavaScript

Si vous avez besoin d’exécuter un script JavaScript, vous devez utiliser la méthode « executeJavascript » avec le nom de la méthode à exécuter en paramètre :

Vous pouvez aussi passer des arguments à votre méthode JavaScript et de manière asynchrone avant de récupérer le résultat :

Il est aussi possible d’écrire directement du code JavaScript au sein de cette méthode :

3.6  Prendre une capture d’écran

Vous pouvez prendre une capture d’écran de votre navigateur pendant l’exécution des tests en utilisant la méthode « takeScreenShot() » et passer en paramètre le chemin et le nom du fichier à sauvegarder :

4. Cas concret

Nous allons voir étape par étape comment utiliser FluentLenium au sein d’un projet Liferay.

Nous utiliserons Eclipse comme IDE.

4.1  Créer un nouveau module de test

Afin de séparer mes tests d’IHM, je vais créer un nouveau module pour mon projet que je nomme : « test-ihm » :

Dans File -> New -> Other -> Maven module

img3

4.2  Ajouter la dépendance FluentLenium

Pour ajouter la dépendance FluentLenium à votre projet, ouvrez le fichier « pom.xml » du module précédemment créé et copier le code suivant :


img2

Nous utiliserons AssertJ pour l’écriture de nos tests mais si vous souhaitez utiliser Junit vous pouvez remplacer le code précédent par :

En effet, par défaut, le core de FluentLenium propose un adaptateur pour écrire des tests JUnit mais il existe aussi des adaptateurs pour AssertJ et TestNG

Placez-vous dans le dossier correspondant à votre module puis lancer un build maven en tapant la commande :

img3

4.3  Tests de notre page de login

Nous allons tester la page de login du projet :

img4

Arborescence du projet :

img5

  • Créer le package « fr.ihm.page » dans le dossier src/test/java
  • Créer la classe « AbstractPage.java » et faites la étendre la classe « FluentPage »
  • Créer ensuite la classe « LoginPage.java » et faites la étendre la classe « AbstractPage.java»
  • Notre page de login contient un formulaire avec 2 champs (login et password) et un bouton pour soumettre le formulaire, nous allons les ajouter dans notre classe « LoginPage.java » :

4.4  Création des tests associés

Nous allons tester la page précédemment créée :

  • Créer le package « fr.ihm.integration » dans le dossier src/test/java
  • Créer la classe « AbstractPageTest.java » et faites la étendre la classe « FluentTest »

  • Créer la classe « LoginPageTest.java » et faites la étendre la classe « AbstractPageTest»

4.5  Lancement des tests

  • Démarrer le serveur contenant la webapp à tester
  • Une fois le démarrage terminé, faites un clic droit sur le dossier src/test/java à Run As à Junit Test

img6

  • Tous les tests vont s’exécuter, vous devriez avoir le résultat suivant à la fin de leur exécution :

img7

5.  Automatisation des tests

Nous allons voir comment automatiser le lancement de ces tests durant le cycle de vie du build Maven sans avoir à démarrer manuellement notre serveur Liferay :

  • Dans le fichier « pom.xml » nous allons déclarer 2 profils, un pour les tests en local et l’autre pour les tests sur la plateforme d’intégration :

  • On configure ensuite le build pour lancer nos tests:

  • Nous allons utiliser plusieurs plugins pour l’exécution de nos tests, le premier, nommé « cargo-maven2-plugin » va nous permettre de démarrer/stopper notre serveur Liferay :

  • Le plugin « maven-antrun-plugin » va s’exécuter pendant la phase « clean » du build et va nous permettre de supprimer les fichiers temporaires utilisés par Liferay afin d’exécuter nos tests dans un environnement sain :

  • Le plugin failsafe permet de lancer les tests d’intégration pendant le build maven

  • Le plugin surefire utilisé par le plugin cargo pour lancer les tests

En local, il suffit de taper la commande « mvn clean install » pour builder notre projet et exécuter les tests automatiquement.

Si on souhaite utiliser une solution d’intégration continue comme Jenkins nous devrons préciser le profil de test et taper la commande « mvn clean install –P test ».

6. Conclusion

Nous sommes souvent rebuté à l’idée d’écrire des tests d’intégration pour l’IHM de nos projets car beaucoup d’entre nous savent que l’utilisation de Selenium est complexe et peu maintenable.

Au travers cette présentation, nous avons pu voir qu’il est aisé d’écrire ce type de tests en utilisant FluentLenium.

L’utilisation du pattern page objet rend le code beaucoup plus maintenable et l’API proposée par Mathilde Lemée facilite l’écriture mais aussi la lisibilité de nos tests.

Nous n’avons donc plus aucune excuse pour ne pas l’utiliser au sein de nos projets !

 

7. Annexes

GitHub https://github.com/FluentLenium/FluentLenium
Tutoriel pour tester une webapp à l’aide de FluentLenium, en 5 minutes http://thierry-leriche-dessirier.developpez.com/tutoriels/javaweb/tester-webapp-fluentlenium-5min/
Présentation par Mathilde Lemée http://fr.slideshare.net/MathildeLemee/fluentlenium

You may also like...