Tester du code javascript
Publié le 2/03/2012, par Eric Le Merdy dans Événements, Test, Valtech | 4 Commentaires
Il y a une semaine, Samori Gorce (@shinuza) est venu chez Valtech. L’objectif était de nous faire une démonstration inspirée par son dernier talk au ParisJS et de nous faire participer à une séance de TDD avec du code Javascript.

QUnit
Il a commencé par une présentation de QUnit. Ce framework de test est issu du fameux projet JQuery qui facilite les développements javascript dans le navigateur depuis déjà quelques années. Avec QUnit, on dispose d’une page web qui passe les tests. Il suffit d’importer sa librairie à tester et écrire les tests dans un autre script (exemple de source).

mocha
Mocha est un framework de tests unitaire qui tourne dans nodeJS et dans le navigateur. Nous avons eu l’occasion de le découvrir en détails pendant notre TP.
Tutorial
- Installation de la dernière version de node JS
Les paquets ubuntu de nodejs déploient une version un peu trop ancienne pour mocha. Il faut donc déclarer un repository particulier pour obtenir la dernière version avec le système de gestion de paquet du système:$ sudo apt-get install python-software-properties $ sudo add-apt-repository ppa:chris-lea/node.js
Mise à jour et installation des paquets:
$ sudo apt-get update $ sudo apt-get install nodejs $ sudo apt-get install npm
npm est le gestionnaire de dépendances de nodejs. Mocha est donc installé grâce à npm.
$ sudo npm install mocha -g
Vérifications:
$ node --version v0.6.11 $ npm --version 1.1.0-2 $ mocha --version 0.12.1
- Premier lancement
$ mkdir ~/mocha-tutorial/ $ cd ~/mocha-tutorial $ mocha node.js:201 throw e; // process.nextTick error, or 'error' event on first tick ^ Error: ENOENT, no such file or directory 'test' at Object.readdirSync (fs.js:390:18) at Object.<anonymous> (/usr/lib/node_modules/mocha/bin/_mocha:174:14) at Module._compile (module.js:441:26) at Object..js (module.js:459:10) at Module.load (module.js:348:31) at Function._load (module.js:308:12) at Array.0 (module.js:479:10) at EventEmitter._tickCallback (node.js:192:40)
- Créer la structure du projet
Mocha s’attend à trouver un répertoire test.$ mkdir test $ mkdir lib # Répertoire de sources
- Premier test
var assert = require('assert'); require('../lib/array.js')(); describe('Array#prototype', function() { it('should return the first element of my array', function() { assert.equal([1, 3, 3, 4, 5].first(), 1); }); it('should return the last element of my array', function() { assert.equal([1, 3, 3, 4, 5].last(), 5); }); });
Dans ce premier fichier de test, on importe la librairie d’assertions de mocha
assert. On pourrait aussi utiliser une autre librairie d’assertions comme should.js par exemple.
Le reste du fichier de test est la spécification de deux méthodes qui doivent étendre le prototype de la classeArray:firstetlast.$ mocha node.js:201 throw e; // process.nextTick error, or 'error' event on first tick ^ Error: Cannot find module '../lib/array.js' at Function._resolveFilename (module.js:332:11) (...) at EventEmitter._tickCallback (node.js:192:40)
Comme on pouvait le prévoir, le test ne passe pas.
- Première implémentation : étendre le prototype de la classe Array
Créez le fichierarray.jsdans le répertoirelibmodule.exports = function() { Array.prototype.first = function() { return this[0]; }; Array.prototype.last = function() { return this[this.length - 1]; }; };
module.exportsfait partie de nodejs et permet d’isoler le contexte d’exécution dans un environnement restreint au test. C’est utile en particulier ici puisqu’on modifie le prototype de la classeArray.$ mocha .. ✔ 2 tests complete (3ms)
Les deux points montrent ici qu’on a exécuté deux tests. Dans le cas de tests plus long, ils permettent de montrer l’avancement (comme dans phpunit et d’autres frameworks de test probablement).
- Changer la sortie des tests
Mocha peut représenter le résultat des tests de différentes façons. Par exemple, on peut demander une sortie de typespec:$ mocha --reporter spec Array#prototype ✓ should return the first element of my array ✓ should return the last element of my array ✔ 2 tests complete (3ms)
Pour connaître la liste des
reportersdisponibles :$ mocha --reporters dot - dot matrix doc - html documentation spec - hierarchical spec list json - single json object progress - progress bar list - spec-style listing tap - test-anything-protocol landing - unicode landing strip xunit - xunit reportert teamcity - teamcity ci support json-stream - newline delimited json events
Les connaisseurs auront tout de suite remarqué le reporter
xunitqui leur permettra d’obtenir le résultat des tests dans leur usine logicielle préférée. - Deuxième test : test d’une fonction asynchrone
Créez un fichierhello.jsvar hello = require('../lib/hello.js'); describe('Saying hello', function() { it('should wait before saying hello asynchronously', function(done) { hello(function() { done(); }); }); });
Il s’agit ici de spécifier une fonction asynchrone.
- Implémentation de la fonction asynchrone
Créez un fichierhello.jsdans le répertoirelib:function hello(cb) { setTimeout(cb, 1000); } module.exports = hello;
Le résultat de ce test montre que le test asynchrone a pris une seconde pour s’exécuter :
$ mocha -R spec Saying hello ✓ should wait before saying hello asynchronously (1004ms) Array#prototype ✓ should return the first element of my array ✓ should return the last element of my array ✔ 3 tests complete (1014ms)
Mocha trouve même ça bizarre et affiche ce temps. Dans la console, il colore même ce chiffre en rouge.
- “Mocha is watching”
Il est possible de lancer Mocha en mode “watching”. C’est-à-dire qu’il va inspecter les modifications dans le répertoiretestset repasser les tests en cas de modification. On a donc un feedback de test vraiment très rapide :$ mocha -w ◝ watchingOn est proche du comportement d’un infinitest dans l’IDE Java par exemple.
D’autres frameworks

- FuncUnit
Framework de test fonctionnel basé sur Selenium, JQuery, Qunit et EnvJS. Il Permet de rejouer des événements sur un site web dans un navigateur et dans l’usine logicielle grâce à EnvJS - JS Test Driver
Intégration d’un moteur d’éxécution sous forme d’un serveur dans l’IDE. Les clients sont les navigateurs qui se connectent au serveur pour attendre les tests à faire passer. - jsPerf
Pour tester différentes implémentations de fonctions js dans des navigateurs différents. - Vows
Equivalent de mocha. Ajoute son propre langage d’assertions. Interface sympa. - JSCoverage
Couverture de code par les tests en javascript. - Frameworks MVC : JavascriptMVC – EmberJS – Backbone – KnockoutJS
- CasperJS
Fournit une API au dessus de PhantomJS (navigateur headless) pour facilement scripter des tests fonctionnels
Conclusion
Résumé de la pile de test :
- Côté serveur : mocha est particulièrement adapté pour tester des implémentations serveur nodejs. mocha peut s’éxécute dans Jenkins
- Qunit pour les tests unitaires de composants IHM
- Tests fonctionnels : FuncUnit qui est basé sur Selenium tourne aussi dans Jenkins.
Limiter le “Boilerplate” pour passer les tests.
Voilà un article sympathique, qui montre qu’aujourd’hui on s’intéresse de plus en plus au test de son code JavaScript.
Un petit outil dans la liste des autres frameworks : Jasmine (http://pivotal.github.com/jasmine/) qui a une syntaxe très similaire à Mocha, mais qui propose également un plugin Maven (voir cet article par ex : http://www.lordofthejars.com/2012/02/if-there-aint-all-that-much-to-lug.html).
Excellent article !
Dans la veine des frameworks de tests en Javascript il existe Zombie.js.
Il permet de réaliser des tests côté client en simulant un navigateur ! Un Sélénium ou un FuncUnit sans Brwoser si vous préférez!
A préciser tout de même qu’il s’agit d’un module Node.js! Donc si vous utilisez Node.js allez jeter un oeil!
http://zombie.labnotes.org/
Great blog here! Also your site loads up fast! What host are you using?
Can I get your affiliate link to your host? I wish my site loaded up as quickly as yours
lol
Here, I must point the latest poverty wages to get a
family of four is $22,350 if a family is depending on a
one-income household making $25,000, shame for the employer because that’s only $2,650 across the poverty level. So, carrying diapers around or disposing them can be done in fashion too.