Dans son article sur les meilleures pratiques du test logiciel, Daniel Cohen-Zardi explique l’importance des tests et leur impact sur la qualité des logiciels. Attardons-nous un instant sur les tests unitaires dans les projets JavaScript et voyons ensemble comment utiliser Jasmine et Karma, des outils qui ont pour but de renforcer la qualité et limiter le risque de régression d’une application JavaScript.
Le framework de tests Jasmine
Jasmine est un framework de tests JavaScript au même titre que NUnit pour .NET ou JUnit pour le langage Java. Il permet de définir des tests, organisés par suites :
// déclaration d'une suite de tests
describe("Arithmetic tests", function() {
// avant chaque test
beforeEach(function() {
// whatever
});
// définition d'un test
it("2 + 2 should be equal to 4", function() {
var a = 2 * 2;
expect(a).toEqual(4);
});
});
Le framework Jasmine est très bien documenté. Voici quelques fonctionnalités phares, mais je vous recommande de parcourir les nombreux exemples afin que vous soyez plus que convaincus.
Vérification des résultats obtenus
Nous pouvons vérifier que le résultat obtenu est conforme à nos attentes. S’il ne l’est pas, le test échouera.
expect(myVar).toBe(...) // comparaison stricte -> ===
expect(myVar).toEqual(...) // test d'équivalence
expect(myVar).toBeDefined() // variable définie (contraire: toBeUndefined)
expect(myFunc).toThrow(); // pour tester que l'exécution d'une fonction déclenche une exception
Ces méthodes sont appelées des matchers. Il en existe beaucoup d’autres et il est également possible d’en créer.
Mocks, stubs et espions
Jasmine permet de simuler des comportements et des résultats attendus avec des mocks. Nous pouvons, par exemple, mocker une dépendance dont le but est de contacter un service web, afin de vérifier que notre code appelle effectivement cette dépendance mockée avec de bons arguments. Nous pouvons voir aussi comment notre code réagit si le mock retourne différentes valeurs, ou s’il déclenche une exception.
describe("Spies examples", function() {
var wsMock, ctrl;
beforeEach(function() {
// fausse implémentation de la couche client web service
wsMock = {
getCustomer: function(id) {
return { id: id, ... };
}
};
// instanciation de l'objet que nous voulons tester
// imaginons qu'il utilise la couche web service et effectue d'autres traitements
ctrl = createControllerWeWantToTest(wsMock);
});
it("controller should call the web service with an integer ID", function() {
// on espionne l'appel à wsMock.getCustomer
spyOn(wsMock, 'getCustomer').and.callThrough();
var id = 1;
var customer = ctrl.findCustomerById(id);
// notre mock a bien été appelé avec un ID numérique, et le résultat final correspond
expect(wsMock.getCustomer).toHaveBeenCalledWith(jasmine.any(Number));
expect(customer).toBeDefined();
expect(customer.id).toBe(id);
});
it("controller should throw an application error when web service throws an exception", function() {
// on modifie le comportement du mock pour déclencher une exception
spyOn(wsMock, 'getCustomer').and.throwError("E194 - Internal error");
expect(function() {
ctrl.findCustomerById(1);
}).toThrowError("An error occured while retrieving the customer");
});
});
Karma, l’exécuteur de tests
Maintenant que nous avons codé nos premiers tests, nous avons besoin de les exécuter. Pour cela, il existe de nombreuses façons de le faire. J’ai choisi Karma, un exécuteur de tests (test runner) développé par les créateurs d’AngularJS. Il exécute les tests sur le navigateur de votre choix et peut générer divers rapports, selon la configuration et les extensions installées. Karma fonctionne avec Node. js, installons donc la version 6 LTS.
Installation de Karma et de ses extensions
Maintenant que Node. js est installé, déplacez-vous dans le dossier du projet avec un terminal et lancez les commandes suivantes :
npm init --force
npm install --save-dev karma
npm install --save-dev karma-jasmine
npm install --save-dev karma-phantomjs-launcher
Toutes ces commandes méritent quelques explications. Après avoir initialisé la configuration Node. js et installé Karma, nous :
- Installons l’extension qui permet de lire les tests Jasmine
- Installons PhantomJS, un navigateur sans IHM ultra rapide qui fournit un contexte d’exécution pour les tests JavaScript
Configuration de Karma
Un fichier de configuration karma. conf. js doit être placé à la racine du projet. Voici un exemple qui devra être légèrement modifié en fonction du chemin de votre code source et les librairies que vous utilisez :
module.exports = function(config) {
config.set({
frameworks: ['jasmine'],
files: [
'www/lib/ma-librairie.js', // on référence les librairies
'www/app/**/*.js', // ... le code source
'test/**/*.js' // ... et les tests unitaires
],
exclude: [],
reporters: ['progress'], // karma affichera les résultats des tests dans la console
browsers: ['PhantomJS'],
plugins: [
'karma-jasmine',
'karma-phantomjs-launcher'
],
singleRun: true,
port: 9876
})
};
Il existe beaucoup d’extensions pour Karma, certaines sont très intéressantes, notamment dans le cadre de l’intégration continue :
- karma-coverage : Génère les statistiques de couverture de code au format HTML. Compatible avec TeamCity.
- karma-teamcity-reporter : Permet de publier le résultat des tests dans TeamCity.
- karma-jenkins-reporter : Permet de publier le résultat des tests dans Jenkins.
Exécution des tests unitaires
Il suffit de lancer la commande node node_modules\karma\bin\karma startLe résultat :
23 10 2016 22:52:11.636:INFO [karma]: Karma v0.13.22 server started at http://localhost:9876/
23 10 2016 22:52:11.651:INFO [launcher]: Starting browser PhantomJS
23 10 2016 22:52:13.225:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket ptSbeflHpVQj-0tjAAAA with id 78640437
PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 2 of 2 SUCCESS (0 secs / 0.044 secs)
Conclusion
Maintenant que vous avez mis en place tout ce qu’il faut pour exécuter vos tests unitaires JavaScript, il ne vous reste plus qu’à en écrire ! Pour terminer, j’aimerais parler des environnements de développement. Bien que pro-Microsoft (Visual Studio Enterprise et Code), j’ai trouvé qu’il était plus facile de développer des applications JavaScript avec l’éditeur WebStorm de JetBrains (<3 ReSharper). En effet, celui-ci fournit une meilleure complétion de code et permet d’exécuter des tests Jasmine / Karma en temps réel, avec la couverture de code affichée à côté du nom des fichiers.