Pages

lundi 19 janvier 2015

Comment écrire vos tests javascript avec Jasmine (2/2)

Après avoir introduit Jasmine dans un précédent article, nous allons aujourd'hui finir notre voyage dans les méandres de ce framework de tests Javascript.




Setup et teardown
Dans tout framework de tests il est important de bénéficier d'un mécanisme pour initier le contexte avant l'exécution et pour revenir à l'état initial après l'exécution d'un test. Pour cela, Jasmine propose 4 méthodes
  • beforEach est appellé avant l'exécution de chaque test et
  • afterEach après l'exécution. 
  • beforeAll est invoqué une seule fois avant le lancement des tests et 
  • afterAll à la fin de tous les tests 

Pour partager des variables entre vos tests et vos méthodes d'initialisation ou de nettoyage vous pouvez utiliser des variables de portées globales

describe("Test beforeEach and afterEach", function() {
    var hello = 0;

    beforeEach(function() {
        hello += 1;
    });

    afterEach(function() {
        hello = 0;
    });

    it("hello have to be incremented", function() {
        expect(hello).toEqual(1);
    });

    it("hello have always the same value", function() {
        expect(hello).toEqual(1);
    });
});


Mais vous pouvez aussi utiliser this et le même exemple devient

describe("Test beforeEach and afterEach with this keyword", function() {
    beforeEach(function() {
        this.hello = !this.hello ? 1 : this.hello + 1;
    });

    afterEach(function() {
        this.hello = 0;
    });

    it("hello have to be incremented", function() {
        expect(this.hello).toEqual(1);
    });

    it("hello have always the same value", function() {
        expect(this.hello).toEqual(1);
    });
});


Comment simuler les collaborateurs

Comme je l'ai déjà expliqué plusieurs fois dans mes articles, il est important dans un test unitaire d'isoler la classe ou la fonction à tester du reste de l'application. Il faut donc simuler le comportement des différents collaborateurs (objets, fonctions...). Jasmine propose de créer des mocks en utilisant ce qu'ils appellent des spies.

Le but d'un spy est de surcharger le comportement (to stub) de n'importe quelle fonction, de traquer les appels à cette fonction ainsi que les arguments passés.

Prenons un exemple. Pour afficher le nom de mon article j'utilise la fonction Javascript suivante

function getArticleTitle(articleService, id){
    //Je recherche un article
    var article = articleService.getById(id);
    return article ? article.name : "Article not found id=" + id;
}

Cette fonction utilise un service permettant d'appeler un service REST récupérant l'article ayant l'id passé en paramètre. Pour pouvoir tester unitairement la fonction getArticleTitle je vais simuler le comportement de articleService.


Imaginons que le service ressemble pour le moment à

function ArticleService(){
    this.getById = function(id){
        //Ici on appelle le serveur par exemple
        //...
        return {id : id, name : 'Implem reelle'};
    };
}

Dans mon test je vais surcharger le comportement de la méthode getById en utilisant la fonction spyOn

describe("BlogService ", function () {
    var articleService;

    beforeEach(function () {
        articleService = new ArticleService();
    });

    afterEach(function () {
        articleService = undefined;
    });

    it("find article name without spy", function () {
        expect(getArticleTitle(articleService, 1)).toBe('Implem reelle');
    });

    it("find article name with a spy", function () {
        spyOn(articleService, 'getById').and.returnValue({name : 'Test en Javascript'});
        expect(getArticleTitle(articleService, 1)).toBe('Test en Javascript');
    });
});

L'avantage des mocks c'est qu'avec eux je peux tester le cas où je n'ai aucun retour

    it("don't find article name", function () {
        spyOn(articleService, 'getById').and.returnValue(undefined);
        expect(getArticleTitle(articleService, 1)).toBe('Article not found id=1');
    });

Si vous voulez exécuter un traitement plus complexe que retourner une valeur vous pouvez utiliser la méthode and.callFake() ;


Un dernier exemple pour voir comment simuler une exception

    it("find article name throw exception", function () {
        spyOn(articleService, 'getById').and.throwError('Erreur service');

        expect(function(){
            getArticleTitle(articleService, 1);
        }).toThrowError('Erreur service');1
    });


Conclusion

Jasmine apporte toutes les fonctionnalités permettant de mettre en place des tests en Javascript. La particularité de Jasmine est d'exécuter les tests dans un navigateur internet. Si vous voulez exécuter vos tests sur un moteur Javascript NodeJS vous pouvez vous pencher vers Mocha ou sinon utiliser un navigateur alléger comme PhantomJS.

N'hésitez pas à consulter la documentation liée au projet Jasmine ou de consulter les sources mises à disposition sous Github.

La prochaine fois nous continuerons notre exploration des tests en Javascript avec Karma

Aucun commentaire:

Enregistrer un commentaire

Remarque : Seul un membre de ce blog est autorisé à enregistrer un commentaire.