Selenium, allons plus loin 2/2

Dans une première partie (Selenium, allons plus loin 1/2), j’ai eu l’occasion de vous présenter la mise en place de l’industrialisation des tests avec Selenium. Dans cette seconde partie, j’aborde les problématiques de répétabilité des tests Selenium.

L’objectif des lignes qui vont suivre est de comprendre l’intérêt de la répétabilité en répondant aux questions suivantes :

  • Répétabilité ? Qu’est-ce que cela signifie ?
  • Comment puis-je rendre mes tests Selenium répétables à l’infini ?

Contexte des tests

Avant toute chose, revenons sur l’industrialisation des tests et ses objectifs.

Cette dernière doit permettre d’assurer un suivi de la qualité fonctionnelle du projet. Pour cela, il faut être en mesure d’assurer l’exécution des tests plusieurs fois durant la période où le projet est en cours de construction. Cette exécution doit être effectuée de manière automatique suivant une politique de lancement. Ce point est l’une des raisons majeures pour la mise en place d’une UDD (Usine De Développement) comme un Hudson/Jenkins, sur un projet.

Remarque : J’ajouterai qu’au travers de l’automatisation des tests, et de sa simplicité de suivi, c’est l’adhésion des créateurs de tests qui est en jeu. En effet, plus les actions de mise en place et de contrôle de la conformité d’une application (au travers des tests fonctionnels) sont lourdes, plus compliquée sera l’adoption de ceux qui participent à la qualité d’un projet.

Répétabilité et tests intrusifs

Le rôle du test est de valider le bon comportement du développement effectué ainsi que sa conformité vis à vis des spécifications techniques et fonctionnelles. Il peut être exécuté une ou plusieurs fois dans le temps. Cependant, il est intéressant, voir primordial de valider tout au long de la construction de l’application que la fonctionnalité reste correcte. Malgré tout, il peut arriver que certains développements apportent de l’instabilité sur des développements anciens, il s’agit des fameux effets de bord. Dans le but d’éviter ce type de scénario, il est intéressant de valider au plus tôt dans la chaîne de développement l’absence de régression, en exécutant les tests suivant une politique de build/exécution (sur commit, par CRON, …). C’est dans ce cadre que la notion de répétition émerge, on parle de répétabilité. Ah enfin! Nous y arrivons ….

Mais que se cache-t-il derrière la répétabilité? Affinons cette notion. Un test est répétable si il est exécutable à l’infini et de manière automatique (grâce à l’Intégration Continue par exemple). Jusque-là, à priori, pas trop de problème. Oui mais …

Que se passe-t-il si un test introduit des données dans mon application à chaque exécution et que cette dernière n’accepte pas les doublons (duplication de l’information) ? Si j’exécute de nouveau ce test, il risque de me renvoyer une erreur.

Il est fréquent que nous créions un test intrusif, qui impacte le comportement de son prochain lancement du fait de la modification de son contexte de d’exécution.

J’en veux pour exemple le test suivant :

Le test concerne la création d’un compte sur une application. Admettons que cette phase  soit soumise à certains contrôles tel que l’unicité du trio mail, nom, prénom de l’utilisateur.

Déroulement du test Selenium associé:

Lors de l’enregistrement du test, une nouvelle entrée en base contenant les paramètres du compte est apparue. Dès lors si nous souhaitons exécuter ce dernier, il renverra une information d’erreur. Le contrôle de conformité des données utilisateur va empêcher l’accès à la page attendue par le Selenese (Commande Selenium) suivant.

Constat :

Pour assurer l’exécution d’un test plusieurs fois, il est important que le contexte de test soit cohérent (fonctionnellement). Il faut donc qu’à l’issue de son exécution, le test exécute une procédure lui permettant de revenir à un contexte cohérent. Dans l’exemple, il s’agira de supprimer l’information en BDD (Base De Données). Nous parlons alors de “Procédure de retour arrière” ou “Rollback”

Attention, il peut arriver, pour certaines raisons, qu’un test n’aboutisse pas. Du coup, l’action de retour à l’état zéro ne sera pas effective. Il faut s’assurer de la bonne cohérence de la base avant de lancer un test. Il est alors préférable d’effectuer la suppression de l’information en début de test et non à sa fin.

Et si la donnée n’existe pas encore ?

Pas de problème, rien ne sera supprimé, il ne s’agit que d’un “delete“. Le service renverra que rien n’a été supprimé. Cela signifie que la base est dans un état cohérent pour le test.

Compte tenu des informations que nous venons de mettre en avant, nous pouvons ajouter à la définition de répétabilité la qualité de : non intrusif.

Trois solutions envisagées

La première

Nous pouvons mettre en place une page technique contenant des liens faisant appel à des services de rollback accessibles sous http://domain/rollbackSelenium.html par exemple.

Cette solution fonctionne correctement lors de l’utilisation d’outils tels que Selenium AES et Selenium IDE  (cf. partie 1/2) qui ne proposent pas d’action SQL directe. Ainsi il suffit d’ajouter un Selenese (commande Selenium)  dans le test (Format HTML) de type “Click” après s’être positionné sur la page de rollback.

Cela donnerait les Selenese suivants à ajouter pour chaque test (en début ou fin) :

open /rollbackSelenium.html
clickAndWait link=Suppression_en_base_mon_test_login

Inconvénients :

  • Implique le développement des actions derrières chacun des liens.

La seconde

Nous l’avons vu dans la première partie de cette article, Selenium propose une api de test pour les différentes plateformes de programmation (java, php, .Net, …). Focalisons nous sur l’api Java (le mode opératoire est le même sous les autres plateformes).

A l’image du test TestNG présenté en première partie, celui-ci étend la classe SeleneseTestNgHelper qui propose une méthode tearDown() appelée en fin de test et Setup() exécutée au début.
Dans l’une de ces méthodes, nous allons implémenter le service qui permettra un accès à la BDD et qui effectuera la suppression.

Exemple :

package com.soat.selenium;

import org.testng.annotations.Test;

import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.SeleneseTestNgHelper;

import org.testng.dao.SoatActionDao;

public class testSoat extends SeleneseTestNgHelper {

private SoatActionDao soatActionDao;

@Test public void testTestSoat() throws Exception {

/*
* TestSelenium de login
*/
}

@Override
public void tearDown() throws Exception {
// Appel au dao de suppression du Compte en base de données
soatActionDao.deleteLogin("jairp");
}

public SoatActionDao getSoatActionDao() {
return soatActionDao;
}

public void setSoatActionDao(SoatActionDao soatActionDao) {
this.soatActionDao = soatActionDao;
}
}

Inconvénient :

  • Nécessite l’implémentation de la procédure par un développeur.

La troisième

A l’image de tests unitaires Java (JUnit, TestNG), il est envisageable de générer une base de données (memcache ou physique) contenant un jeu de données révélateur de l’application (compte, droit, données métier, ..) au début de chaque phase de test. Cet exercice est envisageable grâce à des outils comme DBUnit. A l’issue du test la BDD, sera supprimée.

Dans la mise en place de cette solution, le cheminement sera le suivant :

  • Création de l’instance de la base et du schéma
  • Injection de la structure et des données
  • Démarrage du server d’application avec des paramètres de connexion à la BDD pointant sur la base
  • Exécution des tests
  • Arrêt du server
  • Shutdown de la base de données

Inconvénients :

  • La maintenance de ce type de système est coûteuse et nécessite une bonne connaissance du modèle de base.
  • Suivant la volumétrie de la base de données, les tests pourraient s’en trouver ralentis.

Conclusion

La première solution implique de développer une page cachée qui sera appelée par une Selenese avec tous les risques de sécurité que cela comporte. Ainsi, il faudra envisager de sécuriser la page ou de la mettre uniquement à disposition sur un environnement de développement/préproduction pour qu’elle ne soit pas accessible par le tout-venant. Dès lors que cette solution est en place, il est possible d’utiliser toutes les approches Selenium :

  • api de test Selenium
  • directement depuis un script HTML.

Les solutions deux et trois présentent une implication plus forte des équipes de développement, ainsi que la mise en place de tâches techniques et de transformations supplémentaires.

Pour la solution 2 : ajout de la transformation du test HTML vers Java si le test enregistré au travers de Selenium IDE.

Pour la solution 3 : conclusion similaire à la solution 2, à laquelle s’ajoute la maintenance des données de test de la BDD.

Toutes ces solutions nécessitent une collaboration étroite entre celui qui effectue le test (MOA, Recette, PO, …) et le développeur qui implémentera la procédure de retour arrière. Rien de tel alors qu’un peu de proximité pour pallier le problème.

Nombre de vue : 130

AJOUTER UN COMMENTAIRE