Test Logiciel et Assurance Qualité

Aller au contenu | Aller au menu | Aller à la recherche

dimanche 23 mai 2010

5 trucs et astuces pour JUnit

JUnit JUnit est le framework de test unitaires en Java. Il est désormais bien connu des développeurs Java et on le trouve intégré à la majorité des IDE, Eclipse et NetBeans en tête.

Se servir de JUnit est une chose. Ecrire des tests efficaces en est une autre. Ce post n'a pas la prétention de livrer toutes les bonnes pratiques qui entourent JUnit, mais donne quelques trucs qui peuvent servir à un moment ou à un autre.

1- Définissez une classe de base pour vos tests

Un test JUnit doit hériter de junit.framework.TestCase. Cependant, pour un projet donné, on a souvent intérêt à créer une classe de base pour tous les tests JUnit. Par exemple, pour le projet "Titato" :

/**
 * All tests inherit this class.
 */
public abstract clas TitatoTestCase extends 
    junit.framework.TestCase {
}

Puis chaque test du projet hérite de cette classe :

/**
 * Test of ASpecificClass class.
 */
public class ASpecificClassTest extends TitatoTestCase {
  (...)
}

L'intérêt ? Avoir un endroit où définir des méthodes utilitaires qui pourront être utilisées par tous les tests du projet. Par exemple, JUnit ne propose pas d'assertion pour comparer le contenu de tableaux de byte. Si on a souvent besoin d'une telle assertion, TitatoTestCase est l'endroit approprié pour définir une telle méthode : elle sera accessible depuis tous les tests.

2- Pour les larges comparaisons, préférez assertEquals(String, String)

Toutes les assertions se valent... à priori. Pourtant, il y en a une qu'Eclipse traite différemment : la comparaison de chaine. Si on compare deux chaines différentes, Eclipse effectue un diff. Très pratique lorsque les chaines sont longues.

La comparaison :

public void testStrings() {
  assertEquals(
    "This is a string\nAnd this is another one",
    "This is a string\nAnd this is another ONE!");
}

produit :

Comparaison de chaines

Pour tirer parti de cette fonctionnalité, il suffit de rappeler assertEquals(String, String), plutôt qu'une de ses variantes. Prenons une comparaison de liste :

public testGetPeopleList() {
  ArrayList<String> expected = new ArrayList<String>();
  expected.add("John");
  expected.add("Bob");
  expected.add("Paul");
  expected.add("Michael");

  assertEquals(expected, getPeopleList());
}

En exécutant le test tel quel, Eclipse livre un message peu lisible :

junit.framework.AssertionFailedError: expected:<John, Bob, Paul, Michael> but was:<John, Bob, Paul, Greg, Michael>

Il y a une différence, mais quelle est-elle au juste ?

En ramenant les listes à des chaines, on se simplifie la vie. Définissons assertEquals(ArrayList<String>, ArrayList<String>), probablement dans la classe mère des tests JUnit du projet, afin que celle-ci soit utilisable partout :

public void assertEquals(
    ArrayList<String> expected, 
    ArrayList<String> observed) {
  // Let's call assertEquals(String, String)
  assertEquals(toString(expected), toString(observed));
}

private String toString(ArrayList<String> list) {
  String result = "";
  for (String s: list) {
    result += s + "\n";
  }
  return result;
}

Cette fois-ci, l'erreur est évidente :

Assertion pour les ArrayList

Dans toString(ArrayList<String> list), il est important de noter qu'on insère des sauts de ligne entre chaque item de la liste. C'est important puisque cela va avoir un impact sur la présentation du diff. Sans cela, Eclipse affiche un diff portant sur une unique ligne. Nettement moins lisible.

3- Ne prenez pas de risque pour le test d'exception

Les tests négatifs nécessitent régulièrement de vérifier qu'on obtient une exception en cas d'appel erroné :

public void testTouchyMethod {
  try {
    // touchyMethod shall throw a SomeException
    touchyMethod();
    fail("An exception was expected");
  }
  catch(SomeException e) {
    // Correct case
  }
}

Le point faible de ce type de construction vient de l'appel à la méthode fail de JUnit, invoquée si touchyMethod retourne au lieu de lancer une exception. Cet appel est vite oublié. Si tel est le cas, le test ne sert à rien, tout en donnant l'impression inverse.

Afin d'éviter ce risque, on peut implémenter un helper :

public abstract class ExceptionTester extends TestCase {
  public abstract void runTestedAction() throws Throwable;

  public ExceptionTester(Class expectedClass) {
    try {
      runTestedAction();
    }
    catch (Throwable t) {
      assertEquals(expectedClass, t.getClass());
      return;
    }
    fail("Expected " + expectedClass + " but got no error");
  }
}

Puis, lorsqu'on a besoin de vérifier un lancement d'exception :

public void testFailingMethod() {
  new ExceptionTester(Exception.class) {
    @Override
    public void runTestedAction() throws Throwable {
      touchyMethod();
    }
  };
}

Cette seconde version n'est guère plus compacte, mais là n'est pas l'intérêt. Les avantages :

  • Par le jeu de la complétion des IDE modernes, elle est beaucoup plus rapide à saisir. Notamment, Eclipse va déclarer runTestedAction de lui-même.
  • Cette forme est plus sûre : pas d'appel à fail à oublier.

4- Utilisez des fichiers sans dépendre de leur chemin absolu

Un test doit pouvoir d'exécuter dans tout environnement. Lorsqu'on a besoin d'utiliser un fichier à partir d'un test, il est tentant d'utiliser un chemin absolu mais nous savons tous où cela mène...

La solution généralement recommandée est d'utiliser getResource et getResourceAsStream :

InputStream is = this.getClass().getResourceAsStream("data.txt");

C'est un début. Utiliser ces méthodes directement présente néanmoins une difficulté. Comme elles prennent comme référence le répertoire de la classe, le test JUnit dans notre cas, on doit souvent se fendre d'un conséquent "../../../.." avant d'atteindre le répertoire ciblé.

Une bonne technique est de régler ces problème une fois pour toute, dans la classe mère des tests JUnit du projet :

public InputStream getResourceAsStream(String path) 
    throws IOException {
  // Get the path of the JUnit test base class
  URL url = SampleTestCase.class.getResource(
    "TitatoTestCase.class");
  // Get the directory of the class
  // (ie. the TitatoTestCase.class file)
  // This method assume that TitatoTestCase is not located 
  // in a JAR file
  File file = new File(url.getPath());
  // Here, the "/../" depends on the project layout
  return new FileInputStream(file.getParent() + "/../" + path);
}

Cette méthode doit être adaptée pour chaque projet :

  • "TitatoTestCase.class" dépend du nom de la classe de base des tests JUnit.
  • Dans la dernière ligne, "/../" est destiné à se placer au niveau du projet. Ce composant dépend de l'endroit où est compilée la classe ainsi que son package.

Enfin, chaque test peut ouvrir un fichier :

getResourceAsStream("test/test_data/data.txt");

5- Test de séquences complexes : utilisez des traces sous la forme de String

Certain tests consistent à vérifier que telle ou telle méthode a bien été appelée. C'est régulièrement le cas lorsqu'on implémente le design pattern Template method.

Prenons l'exemple d'une classe FileHelper. Cette classe possède une méthode process qui prend en paramètre un nom de fichier ainsi qu'un FileProcessor. FileProcessor est une interface dotée de 3 méthodes :

  • fileOpened(String fileName) : appelée lorsque le fichier à traiter est ouvert ;
  • lineRead(String line) : appelée pour chaque ligne du fichier traité ;
  • fileClosed() : appelé lorsque le fichier traité est fermé.

Lorsqu'on appelle FileHelper.process("myFile.txt", aProcessor), on s'attend à la équence suivante :

  • aProcessor.fileOpened est appelé avec "myFile.txt" ;
  • aProcessor.lineRead est appelé pour chaque ligne du fichier ;
  • aProcessor.fileClosed est appelé.

Comment tester FileHelper.process ? Une solution pratique est de tracer l'exécution au sein d'une instance de FileProcessor et de comparer cette trace avec le résultat attendu.

On commence par créer un fichier d'exemple, nommé data_for_filehelper_process.txt :

This is a sample file
to test FileHelper.process
Bye!

On implémente FileProcessor. Cette implémentation ne fait rien d'autre que sauver la trace des méthodes qui sont appelées :

public class TestProcessor implements FileProcessor {
  String trace = "";
  public void fileOpened(String fileName) {
    trace += "fileOpened(" + fileName + ")\n";
  }
  public void lineRead(String line) {
    trace += "lineRead(" + line + ")\n";
  }
  public void fileClosed() {
    trace += "fileClosed()\n";
  }
  public String getTrace() {
    return trace;
  }
}

Il ne reste plus qu'à implémenter le test :

public void testProcess() {
  TestProcessor processor = new TestProcessor();
  // For an idea of how getResourcePath should work, 
  // see previous section above
  FileHelper.process(getResourcePath(
    "test/test_data/data_for_filehelper_process.txt"), 
    processor);
  // Check the trace
  assertEquals(
    "fileOpened(data_for_filehelper_process.txt)\n" +
    "lineRead(This is a sample file)\n" +
    "lineRead(to test FileHelper.process)\n" +
    "lineRead(Bye!)\n" +
    "fileClosed()\n", 
    processor.getTrace());
}

Si FileHelper.process est buggué et omet de lire la dernière ligne du fichier, on obtiendra sous Eclipse :

Trace testing

Bon test avec JUnit !

samedi 13 mars 2010

Tutoriel : Tester une application Android avec Monkey

Android Logo Monkey est un outil qui permet de tester une application Android. Plus précisément, il simule des interactions "aveugles" avec l'application à vérifier. Contrairement à la grande majorité des environnements de tests, Monkey n'a pas besoin d'être piloté, ou alors très sommairement : on ne lui indique pas où cliquer, le résultat attendu, etc. Il génère des interactions quelconques sans ce soucier de la logique applicative et signale les erreurs évidentes, comme les exceptions non traitées.

Ce billet explique comment lancer Monkey et exploiter ses résultats. Il fait référence à une application d'exemple fournie avec le SDK Android.

Préparation de l'environnement

Avant de lancer Monkey, nous avons besoin du SDK Android. Suivez les étapes 1 à 3 d'Installing the SDK. Si vous développez sur Android ou si plus simplement vous avez essayé le Hello World, alors vous avez déjà tout ce qu'il faut.

Nous avons également besoin d'une application à tester. Plutôt que d'en écrire une pour l'occasion, nous allons partir de NotePad, une application d'exemple fournie avec le SDK.

  1. Lancez Eclipse.
  2. Faites File > New > Android Project. Création d'un projet
  3. Dans le wizard, au lieu de créer une nouvelle application, on importe une application d'exemple. Sélectionnez Create project from existing sample, dans le volet Build Target sélectionnez Android 1.6 puis dans la liste Samples choisissez NotePad. Cliquez sur Finish. Wizard Le projet est créé, il apparait dans le Package Explorer, par défaut dans la partie gauche d'Eclipse. Nous allons lancer NotePad, mais pour cela nous avons besoin d'une instance Android virtuelle.
  4. Faites Window > Android SDK and AVD Manager. Android SDK and AVD Manager
  5. Dans la fenêtre Android SDK and AVD Manager, cliquez sur New... Android SDK and AVD Manager - New
  6. Dans la fenêtre Create New AVD, inscrivez Default_AVD en tant que nom, choisissez Android 1.6 - API Level 4 dans la liste Target et entrez une taille de 1024 Mo pour la carte SD. Cliquez sur Create AVD. AVD Creation L'instance virtuelle est maintenant disponible. AVD created Il est tant de lancer Notepad.
  7. Cliquez-droit sur le projet NotesList et sélectionnez Run As > Android Application. Run NotePad L'instance virtuelle se lance et après quelques dizaines de secondes, NotePad est disponible. NotePad
  8. Cliquez sur Menu puis créez une note. NotePad - Add Note
  9. Saisissez du texte et validez. NotePad - Edit Note La note est créée. NotePad - Note Created

Lancer Monkey

NotePad fonctionne et nous pouvons à présent lancer Monkey.

  1. Assurez-vous que l'émulateur est lancé. Si ce n'est pas le cas, suivez les instructions ci-dessus de nouveau pour relancer NotePad.
  2. Ouvrez une console et rendez-vous dans le sous-répertoire tools du SDK Android. New console
  3. Lancez Monkey avec la commande adb shell monkey -p com.example.android.notepad -v 500

Monkey se connecte à l'instance virtuelle et effectue diverses actions, comme le ferait un utilisateur... un utilisateur qui ne sait pas vraiment ce qu'il veut car ses manipulations n'ont aucun but précis : modification hasardeuse de la note existante mais sans sauver, modification du volume, rotation de l'écran... Dans la console, on voit les différentes actions qui sont déclenchées par Monkey tandis que la fenêtre de l'émulateur s'anime au fur et à mesure.

Monkey has finished

Et en cas de bug ?

Monkey vient de jouer avec NotePad sans signaler quoi que ce soit d'anormal. Que se passe-t-il lorsqu'une erreur se produit ? Voyons-voir ça.

  1. Editez NoteEditor.java. Après la ligne 175, insérez throw new RuntimeException("Oh! Un bug!"); afin qu'une exception soit déclenchée lors d'une édition. Insert a bug
  2. Sauvez.
  3. Relancez NotePad. Dans la barre d'outils cliquez sur Run As..., sélectionnez Android Application et faites Ok. Rerun NotePad
  4. A partir de la console, relancez Monkey.

Cette fois-ci, les tentatives de Monkey ne devraient pas se faire sans encombre. Après plus ou moins d'actions, Monkey tombe sur le bug et échoue. Il affiche la stack trace qui permet de retrouver l'origine de l'erreur.

Monkey fails

Le mot de la fin

Monkey a le grand avantage de fonctionner immédiatement, sans nécessiter l'écriture de tests. Naturellement, la contrepartie est cinglante : sans aucune connaissance du fonctionnement attendu de l'application, Monkey ne sait détecter que les erreurs plus bas niveau, celles qui provoquent une récupération par le système. Attention donc à ne pas tomber dans le piège qui consiste à se reposer entièrement sur Monkey, au détriment de véritables tests.

dimanche 10 janvier 2010

Tutoriel Selenium

Logo Selenium SeleniumHQ est un outil de test pour les applications Web. Il permet de vérifier qu'une application se comportera de la même façon quel que soit le navigateur utilisé. Selenium s'utilise ainsi :

  1. Enregistrement d'une séquence : A l'aide d'un plugin Firefox, on enregistre une séquence. Clic sur un lien, saisi d'un formulaire, vérification d'une réponse...
  2. Intégration du test : On intègre le test au sein d'une suite de test, dans le langage et le framework de son choix.
  3. Exécution du test : Le test est joué sur plusieurs navigateurs et plusieurs plateformes afin de valider l'interopérabilité de l'application.

Selenium est indépendant du langage utilisé. On peut tester une application PHP, Java, Ruby on Rails... De plus, Selenium supporte les langages les plus communs pour la programmation Web :

  • C#
  • Java
  • Perl
  • PHP
  • Python
  • Ruby

En plus des langages, Selenium connait les frameworks les plus utilisés. Par exemple, en Ruby on Rails, on pourra générer des tests Test::Unit ou RSpec, au choix. De cette façon, on obtient des tests consistants avec le reste des tests écrits pour l'application.

Dans ce tutoriel, plutôt que de développer une application pour l'occasion, nous allons tester une application existante : le moteur de recherche de Google (un exemple très inspiré, d'autant que c'est aussi l'exemple choisi par les développeurs de Selenium). Nous allons générer un test JUnit que nous allons intégrer au sein d'une suite de test, puis nous exécuterons ce test.

Installation

Nous allons avoir besoin de Selenium IDE :

  1. Lancez Firefox
  2. Allez sur la page de téléchargement de Selenium
  3. Sélectionnez le téléchargement de Selenium IDE Page de téléchargement
  4. Le téléchargement fait apparaitre un bandeau Firefox a empêché ce site (seleniumhq.org) d'installer un logiciel sur votre ordinateur en haut de la page. Cliquez sur Autoriser pour permettre l'installation. Installation bloquée
  5. Dans le popup Installation d'un logiciel, cliquez sur Installer maintenant. Installation d'un logiciel
  6. Dans le popup Modules complémentaires, cliquez sur Redémarrer Firefox pour terminer l'installation. Modules complémentaires

Nous allons aussi utiliser Selenium RC pour exécuter le test :

  1. Allez sur la page de téléchargement de Selenium
  2. Téléchargez Selenium RC Téléchargement de Selenium RC
  3. Décompressez l'archive téléchargée dans le répertoire de votre choix. Par exemple, dans C:\Program Files (x86) (auquel cas Selenium RC est installé dans C:\Program Files (x86)\selenium-remote-control-1.0.1)

Puisque nous allons utiliser JUnit, nous l'installons également :

  1. Allez sur la page de téléchargement de JUnit
  2. Téléchargez le JAR de JUnit Téléchargement de JUnit
  3. Copiez le JAR de JUnit tel quel dans le répertoire de votre choix (il ne faut pas le décompresser). Par exemple, dans C:\Program Files (x86)\junit-4-8-1

Enregistrement

L'installation terminée, nous pouvons créer notre premier test. La première étape consiste à enregistrer la séquence que nous voulons automatiser.

Dans cet exemple, nous testons le moteur de recherche de Google et écrivons un test qui s'assure que le site de Selenium (seleniumhq.org) fait partie des résultats de la première page lorsqu'on lance une recherche Google sur "selenium". L'objet de ce test est évidemment discutable : si le site de Selenium n'apparait pas sur la première page, cela peut être dû à un mauvais référencement de ce dernier, plutôt qu'à un authentique bug de Google. Dans le cadre de ce tutoriel, c'est bien suffisant.

Pour enregistrer la séquence :

  1. Lancez Firefox
  2. Allez sur la page d'accueil de Google
  3. Lancez Selenium IDE à partir de Firefox, dans le menu Outils Lancement de Selenium IDE
  4. Disposez Firefox et Selenium IDE de sorte à voir les deux fenêtres simultanément. Cela n'a rien d'obligatoire, mais il est pratique de voir la fenêtre de Selenium mise à jour au fur et à mesure de l'enregistrement du test.
  5. Saisissez l'URL de la page d'accueil de Google dans le champ Base URL de Selenium IDE. En effet, cette page sera le point de départ de notre test. Disposition Selenium IDE / Firefox
  6. Lancez l'enregistrement en cliquant sur le bouton Record de Selenium IDE. Selenium est maintenant en train d'enregistrer les actions de l'utilisateur dans Firefox : click, saisie... Lancement de l'enregistrement
  7. Jouez la séquence à enregistrer. Saisissez "selenium" dans la page de Google et cliquez sur Recherche Google. On constate que Selenium IDE liste les actions au fur et à mesure. Exécution de la séquence
  8. Ajoutez une assertion. Dans la page de résultat de Google, nous voulons nous assurer qu'un lien vers le site de Selenium est présent. Il apparait effectivement, on peut voir le texte "seleniumhq.org" qui apparait au bas du premier résultat. Sélectionnez ce texte dans Firefox, faites un clic droit et sélectionnez verifyTextPresent seleniumhq.org Ajout d'assertion
  9. Stoppez l'enregistrement. Dans la fenêtre de Selenium IDE, cliquez de nouveau sur le bouton Record pour arrêter l'enregistrement. On constate que Selenium a enregistré la séquence que nous venons de jouer : open / ouvre la page de Google, type q selenium saisit "selenium" dans le champ texte de la page d'accueil de Google, clickAndWait btnG clique sur le bouton Recherche Google et attend la page de résultat et verifyTextPresent seleniumhq.org s'assure que le texte "seleniumhq.org" est bien présent dans la page de résultat. Arrêt de l'enregistrement
  10. Rejouez le test. Maintenant que Selenium a enregistré la séquence, nous pouvons la rejouer à loisir. Cliquez sur le bouton Play entire test suite. Selenium IDE joue le test "pour de vrai" en pilotant Firefox. On voit ce dernier aller sur la page d'accueil de Google, saisir "selenium" et charger la page de résultat. Selenium IDE liste ce qu'il a exécuté dans l'onglet Log. On constate que l'assertion finale est également évaluée : si "seleniumhq.org" n'apparaissait pas dans la page de recherche, Selenium le signalerait et le test échouerait. Exécution du test

Intégration

Pour le moment, nous avons un test que nous pouvons jouer à partir d'une interface graphique. C'est un début, mais il faut aller plus loin :

  • Exécution dans d'autres navigateurs : Développer avec Firefox pourquoi pas, mais il faut s'assurer que l'application fonctionne aussi avec Internet Explorer, Safari et les autres.
  • Gérer de nombreux tests : Dans ce tutoriel, on se contente d'un test. Dans un cas réel, on a plusieurs dizaines, centaines voir milliers de tests. Cette interface graphique n'est pas viable pour un tel usage.
  • Tests intégrés : Jouer le test à partir de l'interface graphique est pratique lorsqu'on le met au point. En revanche, cela n'est plus praticable lorsqu'on veut jouer le test au même titre que les autres tests de l'application (tests unitaires, etc.). Les tests générés avec Selenium doivent pouvoir être lancés dans le cadre d'une intégration continue, etc.
  • Modification et déclinaison du test : Nous pourrions souhaiter décliner notre test de plusieurs façons. Par exemple, en recherchant différents termes. Avec Selenium IDE, notre seule option est de jouer le scénario encore et encore pour créer nos tests. Cela va vite devenir ennuyeux.

L'étape d'intégration est très rapide car Selenium génère directement un test JUnit pour nous :

  1. Dans Selenium IDE, sélectionnez Options > Format > Java (JUnit). Selenium affiche alors notre test au format JUnit. On reconnait les dfférentes étapes, mais "à la Java" : selenium.open("/") pour ouvrir la page d'acueil de Google, etc. Sélection du format
  2. Copiez le contenu du test, collez-le dans un fichier SearchTest.java que vous créez n'importe où.
  3. Supprimez la mention du package. Dans Search.java, supprimez la ligne de déclaration du package (package com.example.tests;). Dans un cas réel, nous devrions spécifier un package relatif à l'entité pour laquelle nous développons. Dans le cadre de cet exemple, nous allons au plus simple.
  4. Changer le nom de la classe pour SearchTest. Autrement dit, public class Untitled devient public class SearchTest.
  5. Changer le nom de la méthode de test pour testSearch.

Le test définitif :

import com.thoughtworks.selenium.*;
import java.util.regex.Pattern;

public class SearchTest extends SeleneseTestCase {
  public void setUp() throws Exception {
    setUp("http://www.google.fr/", "*chrome");
  }
  public void testSearch () throws Exception {
    selenium.open("/");
    selenium.type("q", "selenium");
    selenium.click("btnG");
    selenium.waitForPageToLoad("30000");
    verifyTrue(selenium.isTextPresent("seleniumhq.org"));
  }
}

A présent nous compilons ce test. La séquence qui suit est pour Windows. Si vous utilisez un autre environnement, vous devrez adapter certaines commandes :

  1. Ouvrez une console. Faites Touche Windows + R, puis demandez à lancer le programme cmd.
  2. Définissez l'emplacement de Selenium RC en définissant la variable SELENIUM_RC_HOME. Par exemple, set SELENIUM_RC_HOME=C:\Program Files (x86)\selenium-remote-control-1.0.1
  3. Définissez l'emplacement de JUnit en définissant la variable JUNIT_HOME. Par exemple, set JUNIT_HOME=C:\Program Files (x86)\JUnit-4-8-1
  4. Placez-vous dans le répertoire où vous avez créé SearchTest.java
  5. Compilez le test avec la commande javac -cp "%JUNIT_HOME%\junit-4.8.1.jar;%SELENIUM_RC_HOME%\selenium-java-client-driver-1.0.1\selenium-java-client-driver.jar" SearchTest.java. Vous devrez peut-être adapter cette commande si vous avez téléchargé une version plus récente de JUnit ou Selenium RC.

Le test est désormais intégré aux autres tests unitaires de l'application. De plus, comme il s'agit de véritable code et non d'une séquence figée, nous pouvons modifier le test pour jouer la séquence plusieurs fois, par exemple avec différents termes de recherche.

Exécution

Maintenant que nous avons un test compilé, nous pouvons l'excuter. Dans ce post, nous ne verrons qu'une façon de le lancer. Cependant, il existe plusieurs options, selon ce que nous attendons de nos tests.

Exécution simple

C'est le mode par défaut, celui qu'utilisent les développeurs pour vérifier leurs réalisations. Le test est lancé depuis la ligne de commande ou depuis un IDE et le résultat est utilisé sur le champ : si bug il y a, il est fixé !

Lorqu'on exécute un test avec Selenium, celui-ci est joué dans un véritable navigateur Web, et non par envoi direct de requêtes HTTP, par exemple. Pour réaliser cela, Selenium utilise un serveur. Ce serveur reçoit les requêtes du test ("ouvrir une page", "cliquer", etc.) et ouvre un navigateur qu'il pilote pour exécuter les commandes du test. Par conséquent, pour lancer SearchTest, nous devons d'abord lancer le serveur Selenium :

  1. Ouvrez une nouvelle console.
  2. Définissez l'emplacement de Selenium RC en définissant la variable SELENIUM_RC_HOME. Par exemple, set SELENIUM_RC_HOME=C:\Program Files (x86)\selenium-remote-control-1.0.1
  3. Ajouter Firefox dans votre PATH. Par exemple, si Firefox est installé dans C:\Program Files (x86)\Mozilla Firefox, utilisez set PATH=%PATH%;C:\Program Files (x86)\Mozilla Firefox
  4. Lancez le server Selnium avec la commande java -jar "%SELENIUM_RC_HOME%\selenium-server-1.0.1\selenium-server.jar"

Nous sommes maintenant prêts à lancer le test :

  1. Reprenez la console que vous avez utilisée pour compiler le test, celle où JUNIT_HOME et SELENIUM_RC_HOME sont définies et pour laquelle le répertoire courant contient le test compilé.
  2. Lancez le test avec la commande java -classpath "%JUNIT_HOME%\junit-4.8.1.jar;%SELENIUM_RC_HOME%\selenium-java-client-driver-1.0.1\selenium-java-client-driver.jar;." junit.textui.TestRunner SearchTest

A l'exécution de cette dernière commande, Selenium RC lance une instance de Firefox et on peut voir le test se dérouler. Cela étant dit, ce n'est pas de voir le navigateur qui nous importe, mais le résultat : à la fin de l'exécution, SearchTest est passed, comme tout test JUnit exécuté avec succès. Il n'y a pas d'intervention manuelle.

Validation, Régression, Intégration continue...

Au delà de l'exécution simple, Selenium permet d'exécuter des tests automatisés à toutes les étapes de la vie du projet :

  • Intégration Continue. Ces tests sont de parfaits condidats pour une exécution fréquente et programmée : toutes les nuits, toutes les semaines...
  • Test de Régression. Comme ils sont automatisés, ces tests peuvent être utilisés par les développeurs comme tests de régression, jouables facilement et rapidement.
  • Test de validation. Naturellement, on peut se servir de ces tests pour valider l'application avant livraison. Une fois encore, l'automatisation fait qu'on ne devrait pas se priver de les jouer.
  • ...

Test d'interopérabilité

Une particularité de Selenium est de lancer les tests sur un véritable navigateur. Comme celui-ci est capable de gérer les principaux navigateurs et qu'il peut s'exécuter sur les principales plateformes, il est l'outil idéal pour vérifier l'interopérabilité de l'application : "Si mon test passe avec succès à partir de Firefox exécuté sous Windows, le fera-t-il avec Safari exécuté sous Mac ?" Selenium permet de répondre à cette question, une fois de plus de façon automatisée.

Le test d'interopérabilité peut être "fait maison" : on se procure machines et navigateurs, on lance différents serveurs Selenium et le tour est joué. Cela demande toutefois pas mal d'efforts : gestion de plateformes différentes, gestion des ressources (deux testeurs ne doivent pas utiliser le même serveur en même temps)... Des entreprises fournissent des solutions de test à la demande pour éviter ces problèmes.

Test de charge

Les tests Selenium peuvent servir de base au test de charge. Au lieu de jouer un test à la fois, on en exécute... un grand nombre ! Comme pour le test d'interopérabilité, ce principe nécessite une certaine organisation pour être mis en œuvre.

Selenium est un outil puissant, élégant et facile à prendre en main. L'essayer c'est l'adopter ! Faites l'essai !