Le Test Driven Development au secours de Javascript !
Travaillant avec les technos Web, j'ai souvent été confronté à Javascript. Java-iste dans l'âme, j'ai été un peu rebuté par ce langage interprété (non compilé), faiblement typé, basée sur la notion de prototype (donc sans classe !)… bref, trop souple pour être vraiment sérieux !
Si on ajoute à cela qu'il existe un moteur par version de navigateur (actuellement on a Chakra chez IE9, V8 pour Chrome, TraceMonkey chez Firefox3.5, SquirrelFish pour Safari ou encore Carakan pour Opera10…) ce sont les maux de tête assurés !
La solution: le TDD ! Cette méthode de développement est une bonne façon d'avoir un retour rapide sur son code et ainsi, de compenser le côté "non-compilé" de Javascript. De plus, les tests unitaires sont particulièrement importants lorsque le typage est dynamique (comme c'est le cas en Javascript, mais aussi en Ruby, Groovy, Python, etc.). Dans ces environnements, c'est le harnais de test produit par le TDD qui permettra au développeur d'avoir la confiance suffisante pour faire du refactoring.
Il existe de nombreux frameworks de tests unitaires Javascript. On retiendra en particulier QUnit (l'outil de tests officiel de JQuery), Jasmine (orienté BDD et successeur de JSunit, le pionnier, sorti en 2001) ou encore le YUI Test de Yahoo. Dans cet article, je vous présenterai JsTestDriver. J'ai choisi JsTestDriver pour plusieurs raisons:
- syntaxe xUnit.
- exécution des tests en parallèle sur plusieurs moteurs JS et agrégation des résultats.
- plugin Eclipse et IntelliJ (alors que la plupart des framework de test JS s'exécute sur le browser, ce qui, en mode TDD, oblige à switcher sans arrêt entre son IDE et son browser)
- côté industrialisation: il est possible de faire de l'intégration continue et d'obtenir des indicateurs de couverture de code.
- la communauté est active et la road-map intéressante.
Architecture
JsTestDriver s'exécute sous la forme d'un serveur (maître) auquel on attache des navigateurs (esclaves).
Le serveur reçoit les sources JS à tester et les déploie sur chacun des navigateurs (au passage, on évite les problèmes de cache associés aux ressources Javascript).
Les navigateurs exécutent les tests et renvoient le résultat au serveur JsTestDriver qui les compile.
Pratique: le plugin Eclipse intègre à la fois la partie serveur et la partie client.
Action !
Je vous propose un petit exemple en 5 étapes, sous Eclipse:
1. Configuration de l'environnement
Installer le plugin Eclipse JsTestDriver depuis http://js-test-driver.googlecode.com/svn/update/
Ce plugin rajoute une nouvelle vue à l'IDE. Pour l'afficher, il faut la sélectionner dans le menu Windows > Show View.
Dans Windows>Préférence>JsTestDriver, définir le port qui sera utilisé par le serveur ainsi que les différents browsers sur lesquels on souhaite tester.
2. Configuration du projet
Créer le fichier de config jsTestDriver.conf à la racine du projet:
server: http://localhost:42442
load:
- src/main/js/*.js
- src/test/js/*.js
Configurer le plugin pour le projet (dans le menu Run > Run configurations)
3. Ecriture d'un test unitaire
Dans src/test/js/cartTest.js. Si vous êtes familiers avec JUnit, la syntaxe ne vous surprendra pas.
CartTest = TestCase("CartTest");
CartTest.prototype.testGetTotalWithOneBook = function() {
var cart = new katapotter.Cart();
var books = [{"title":"first book"}];
assertEquals(8, cart.getTotal(books));
};
Evidemment, ce test ne passe pas !
4. Ecriture du code
Ecrire le code JS minimum permettant de faire passer le test au vert: src/main/js/cart.js
var katapotter = {};
katapotter.Cart = function () {};
katapotter.Cart.prototype.getTotal = function(books) {
return books.length * 8;
};
5. Exécution du test
Démarrer le serveur (bouton accessible sur la vue JsTestDriver).
La barre passe au jaune, ce qui signifie "Serveur démarré, pas de browser associé". En cliquant sur les icônes des navigateurs à utiliser, un nouvel onglet est ouvert dans chacun d'eux (ils sont prêts à recevoir le code JS à tester) et la barre du plugin passe au vert.
un clic droit sur la classe de test permet de lancer le test.
La suite, ce sont les 5 étapes classiques du cycle TDD:
Côté industrialisation
Il existe un jstd-maven-plugin qui permet d'intégrer les tests JsTestDriver dans le processus de Build Maven. Ce plugin peut
- lancer une instance de serveur au moment de l'exécution des tests, exécuter les tests dans un browser local puis arrêter le serveur
- ou utiliser un serveur JsTestDriver standalone
Le second cas est intéressant car il permet de tester sur de nombreux browsers (locaux ou remote). Ainsi, pour attacher un browser à un serveur JsTestDriver standalone (en langage JsTestDriver, on parle de "capturer un browser esclave"), il suffit de faire pointer le browser vers l'URL du serveur JsTestDriver standalone. Il devient donc possible de tester en parallèle sur IE6, IE7, IE8 sur Windows XP et Safari sur MacOS, par exemple !
Pour conclure
Le TDD permet d'obtenir un code robuste: il génère une importante suite composée de petits tests unitaires très centrés sur le code fonctionnel. Ce harnais de tests permet de contrebalancer la (trop) grande souplesse de Javascript et la diversité des moteurs JS.
JsTestDriver est une bonne option pour faire du TDD: il supporte bien le modèle de développement TDD, sa syntaxe est simple, il est rapide et s'intègre agréablement à Eclipse.