Tester du code javascript

Publié par Eric Le Merdy, le 2/03/2012, dans Événements, Test, Valtech

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

  1. 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
  2. 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)
  3. Créer la structure du projet
    Mocha s’attend à trouver un répertoire test.

    $ mkdir test
    $ mkdir lib  # Répertoire de sources
  4. 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 classe Array : first et last.

    $ 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.

  5. Première implémentation : étendre le prototype de la classe Array
    Créez le fichier array.js dans le répertoire lib

    module.exports = function() {
            Array.prototype.first = function() {
                    return this[0];
            };
            Array.prototype.last = function() {
                    return this[this.length - 1];
            };
    };

    module.exports fait 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 classe Array.

    $ 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).

  6. 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 type spec :

    $ 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 reporters disponibles :

    $ 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 xunit qui leur permettra d’obtenir le résultat des tests dans leur usine logicielle préférée.

  7. Deuxième test : test d’une fonction asynchrone
    Créez un fichier hello.js

    var 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.

  8. Implémentation de la fonction asynchrone
    Créez un fichier hello.js dans le répertoire lib :

    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.

  9. “Mocha is watching”
    Il est possible de lancer Mocha en mode “watching”. C’est-à-dire qu’il va inspecter les modifications dans le répertoire tests et repasser les tests en cas de modification. On a donc un feedback de test vraiment très rapide :

    $ mocha -w
     
      ◝ watching

    On 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 : JavascriptMVCEmberJSBackboneKnockoutJS
  • 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.

    2 retours sur “Tester du code javascript”

    1. Romain says:

      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).

    2. Thomas Pons says:

      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/

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

    By submitting this form, you accept the Mollom privacy policy.