Tester le code Node.js avec Mocha et Chai

Introduction

L'écriture de tests unitaires est quelque chose que les débutants et les ingénieurs chevronnés remettent généralement à plus tard pour les phases de développement ultérieures, mais ils sont la clé d'un développement logiciel stable et robuste.

Le principe de base de développement piloté par les tests (TDD) écrit vos tests avant même de commencer à coder. C'est un excellent objectif à atteindre, mais cela demande beaucoup de discipline et de planification lorsque vous essayez de suivre ses principes ! Pour rendre tout ce processus beaucoup plus facile, vous pouvez recourir à des cadres de test et d'assertion faciles à utiliser et puissants, tels que Mocha ainsi que Chai.

Dans cet article, nous allons commencer par vous présenter ces deux bibliothèques, puis vous montrer comment les utiliser ensemble pour créer rapidement des tests unitaires lisibles et fonctionnels.

Chai

Chai est une bibliothèque d'assertions qui fournit à la fois BDD (développement axé sur le comportement) ainsi que TDD (développement piloté par les tests) styles de programmation pour tester le code, et est destiné à être associé à une bibliothèque de test qui vous permet d'organiser des tests. Il est très souvent associé au moka.

Il a trois API principales :

  • should
  • expect
  • assert

var.should.equal(var2)


expect.var.to.be.equal(var2)


assert.equal(var1, var2)

Tout au long de cet article, nous nous concentrerons sur le style BDD en utilisant Chai's expect interface, bien que l'utilisation d'autres interfaces/styles selon votre propre intuition soit parfaitement acceptable. Les assert interface est le cadre d'assertion TDD le plus courant.

expect utilise une API en langage très naturel pour écrire vos assertions, ce qui rendra vos tests plus faciles à écrire et à améliorer plus tard. Cela se fait en enchaînant les getters pour créer et exécuter l'assertion, ce qui facilite la traduction des exigences en code :

let user = {name: 'Scott'};


expect(user).to.have.property('name');

Remarque: Voyez comment vous pouvez à peu près lire l'assertion dans un langage naturel et comprendre ce qui se passe ? C'est l'un des principaux avantages d'utiliser une bibliothèque d'assertion comme Chai !

Quelques autres exemples de ces getters sont :

  • to
  • be
  • is
  • and
  • has
  • have

Un bon nombre de ces getters peuvent être enchaînés et utilisés avec des méthodes d'assertion telles que true, ok, existet empty pour créer des assertions complexes en une seule ligne :

"use strict";

const expect = require('chai').expect;


expect({}).to.exist;
expect(26).to.equal(26);
expect(false).to.be.false;
expect('hello').to.be.string;


expect([1, 2, 3]).to.not.be.empty;


expect([1, 2, 3]).to.have.length.of.at.least(3);

Remarque: Une liste complète des méthodes disponibles est disponible ici.

Vous pouvez également consulter la liste des plugins pour Chaï. Cela facilite grandement le test de fonctionnalités plus complexes.

Prenez chai-http par exemple, qui est un plugin qui vous aide à tester les routes du serveur :

"use strict";

const chai = require('chai');
const chaiHttp = require('chai-http');

chai.use(chaiHttp);

chai.request(app)
    .put('/api/auth')
    .send({username: '[email protected]', password: 'abc123'})
    .end(function(err, res) {
        expect(err).to.be.null;
        expect(res).to.have.status(200);
    });

Organiser des cas de test avec Mocha - describe () et it ()

Mocha est un framework de test pour Node qui vous donne la flexibilité d'exécuter du code asynchrone (ou synchrone) en série. Toutes les exceptions non détectées sont affichées à côté du cas de test dans lequel elles ont été lancées, ce qui permet d'identifier facilement ce qui a échoué et pourquoi.

Il est conseillé d'installer Mocha globalement :

$ npm install mocha -g

Vous voudrez qu'il s'agisse d'une installation globale puisque le mocha La commande est utilisée pour exécuter les tests du projet dans votre répertoire local.

A quoi sert ce morceau de code ?

it() doit renvoyer X. it() définit les cas de test, et Mocha exécutera chacun it() sous forme de test unitaire. Pour organiser plusieurs tests unitaires, nous pouvons describe() une fonctionnalité commune, et ainsi structurer les tests Mocha.

Ceci est probablement mieux décrit avec un exemple concret :

"use strict";
const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });
    });
});

Dans le describe() méthode, nous avons défini une nom du test, appelée #abs(). Vous pouvez également exécuter des tests individuellement par leur nom - cela sera couvert plus tard.

Remarque: Avec les tests Moka, vous n'avez pas besoin de require() l'une des méthodes Moka. Ces méthodes sont fournies globalement lorsqu'elles sont exécutées avec le mocha commander.

Pour exécuter ces tests, enregistrez votre fichier et utilisez le mocha commander:

$ mocha .

  Math
    #abs()
      ✓ should return positive value of given number 


  1 passing (9ms)

La sortie est une ventilation des tests exécutés et de leurs résultats. Remarquez comment le imbriqué describe() les appels sont reportés sur la sortie des résultats. Il est utile d'avoir tous les tests pour une méthode ou une fonctionnalité donnée imbriqués ensemble.

Ces méthodes sont à la base du cadre de test Mocha. Utilisez-les pour composer et organiser vos tests comme bon vous semble. Nous en verrons un exemple dans la section suivante.

Écrire des tests avec moka et chai

La méthode recommandée pour organiser vos tests au sein de votre projet est de les mettre tous dans leur propre /test annuaire. Par défaut, Mocha vérifie les tests unitaires à l'aide des globs ./test/*.js ainsi que ./test/*.coffee. À partir de là, il chargera et exécutera tout fichier qui appelle le describe() méthode.

Consultez notre guide pratique et pratique pour apprendre Git, avec les meilleures pratiques, les normes acceptées par l'industrie et la feuille de triche incluse. Arrêtez de googler les commandes Git et en fait apprendre il!

Il est courant de suffixer les fichiers de test avec .test.js pour les fichiers source qui contiennent des tests Mocha :

├── package.json
├── lib
│   ├── db.js
│   ├── models.js
│   └── util.js
└── test
    ├── db.test.js
    ├── models.test.js
    ├── util.test.js
    └── util.js

util.js dans l' test ne contiendrait aucun test unitaire, juste des fonctions utilitaires pour aider aux tests.

Notes: Vous pouvez utiliser la structure qui vous convient, les tests unitaires sont automatiquement repris.

Lorsqu'il s'agit d'écrire les tests, il est utile de les organiser à l'aide du describe() méthodes. Vous pouvez les organiser par fonctionnalité, fonction, fichier ou tout autre niveau arbitraire. Par exemple, un fichier de test organisé pour décrire le fonctionnement au niveau de la fonction ressemble à :

"use strict";

const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });

        it('should return positive value of given positive number', function() {
            expect(Math.abs(3)).to.be.equal(3);
        });

        it('should return 0 given 0', function() {
            expect(Math.abs(0)).to.be.equal(0);
        });
    });
});

L'exécution des tests vous donnerait alors la sortie :

$ mocha .

  Math
    #abs()
      ✓ should return positive value of given negative number 
      ✓ should return positive value of given positive number 
      ✓ should return 0 given 0 


  3 passing (11ms)

En allant encore plus loin, vous pourriez même avoir des tests pour plusieurs méthodes dans un seul fichier. Dans ce cas, les méthodes sont regroupées par Math objet:

"use strict";

const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });

        it('should return positive value of given positive number', function() {
            expect(Math.abs(3)).to.be.equal(3);
        });

        it('should return 0 given 0', function() {
            expect(Math.abs(0)).to.be.equal(0);
        });
    });

    describe('#sqrt()', function() {
        it('should return the square root of a given positive number', function() {
            expect(Math.sqrt(25)).to.be.equal(5);
        });

        it('should return NaN for a given negative number', function() {
            expect(Math.sqrt(-9)).to.be.NaN;
        });

        it('should return 0 given 0', function() {
            expect(Math.sqrt(0)).to.be.equal(0);
        });
    });
});

Ce qui se traduit par :

$ mocha .

  Math
    #abs()
      ✓ should return positive value of given negative number 
      ✓ should return positive value of given positive number 
      ✓ should return 0 given 0 
    #sqrt()
      ✓ should return the square root of a given positive number 
      ✓ should return NaN for a given negative number 
      ✓ should return 0 given 0 


  6 passing (10ms)

Moka Hooks - avant (), après (), avant chaque () et après chaque ()

Certes, la plupart des tests unitaires ne sont pas aussi simples. Souvent, vous aurez probablement besoin d'autres ressources pour effectuer vos tests, comme une base de données ou une autre ressource externe (ou une maquette/stub de celles-ci). Afin de configurer cela, nous pouvons utiliser un ou plusieurs des éléments suivants Crochet moka méthodes:

  • before(): s'exécute avant tous les tests du bloc donné
  • beforeEach(): S'exécute avant chaque test dans le bloc donné
  • after(): s'exécute après tous les tests du bloc donné
  • afterEach(): S'exécute après chaque test dans le bloc donné

Ces crochets sont l'endroit idéal pour effectuer les travaux d'installation et de démontage nécessaires à vos tests. L'un des cas d'utilisation courants consiste à établir une connexion à votre base de données avant d'exécuter les tests :

"use strict";

const expect = require('chai').expect;
let User = require('../models').User;

describe('Users', function() {

    let database = null;

    before(function(done) {
        
    });

    afterEach(function(done) {
        
    });

    describe('#save()', function() {
        it('should save User data to database', function(done) {
            
        });
    });

    describe('#load()', function() {
        it('should load User data from database', function(done) {
            
        });
    });
});

Avant tous des tests sont exécutés, la fonction envoyée à notre before() La méthode est exécutée (et ne s'exécute qu'une seule fois tout au long des tests), ce qui établit une connexion à la base de données. Une fois cela fait, nos suites de tests sont ensuite exécutées.

Comme nous ne voudrions pas que les données d'une suite de tests affectent nos autres tests, nous devons effacer les données de notre base de données après l'exécution de chaque suite. C'est quoi afterEach() est pour. Nous utilisons ce crochet pour effacer toutes les données de la base de données après chacun cas de test est exécuté, nous pouvons donc repartir de zéro pour les prochains tests.

Exécution de tests Moka

Pour la majorité des cas, cette partie est assez simple. En supposant que vous avez déjà installé Mocha et accédé au répertoire du projet, la plupart des projets doivent simplement utiliser le mocha commande sans arguments pour exécuter leurs tests :

$ mocha


  Math
    #abs()
      ✓ should return positive value of given negative number 
      ✓ should return positive value of given positive number 
      ✓ should return 0 given 0 
    #sqrt()
      ✓ should return the square root of a given positive number 
      ✓ should return NaN for a given negative number 
      ✓ should return 0 given 0 


  6 passing (10ms)

Ceci est légèrement différent de nos exemples précédents puisque nous n'avions pas besoin de dire à Mocha où se trouvaient nos tests. Dans cet exemple, le code de test se trouve à l'emplacement prévu de /test.

Il existe cependant certaines options utiles que vous pouvez utiliser lors de l'exécution de tests. Si certains de vos tests échouent, par exemple, vous ne voudrez probablement pas exécuter la suite entière à chaque fois que vous apportez une modification. Pour certains projets, la suite de tests complète peut prendre quelques minutes. C'est beaucoup de temps perdu si vous n'avez vraiment besoin d'exécuter qu'un seul test.

Pour des cas comme celui-ci, vous devriez dire à Mocha quels tests exécuter. Ceci peut être fait en utilisant le -g or -f options.

Pour exécuter des tests individuels, vous pouvez fournir le -g flag et ajoutez un modèle commun entre les tests que vous souhaitez exécuter. Par exemple, si vous souhaitez exécuter le #sqrt() tests:

$ mocha -g sqrt

  Math
    #sqrt()
      ✓ should return the square root of a given positive number 
      ✓ should return NaN for a given negative number 
      ✓ should return 0 given 0 


  3 passing (10ms)

Notez que le #abs() les tests n'ont pas été inclus dans cette série. Si vous planifiez en conséquence avec vos noms de test, cette option peut être utilisée pour exécuter uniquement des sections spécifiques de vos tests.

Ce ne sont pas les seules options utiles, cependant. Voici quelques options supplémentaires pour Moka que vous voudrez peut-être vérifier :

  • --invert: Inverse -g ainsi que -f allumettes
  • --recursive: Inclure les sous-répertoires
  • --harmony: Activer toutes les fonctionnalités d'harmonie dans Node

Notes: Vous pouvez consulter la liste complète des options en utilisant le mocha -h commande, ou sur cette page.

Où en savoir plus ? Il y a bien plus sur ce sujet que nous ne pouvons couvrir dans un court article, donc si vous voulez en savoir plus, nous vous recommandons de consulter le site officiel Mocha ainsi que Chai Documentation.

Conclusion

Gardez à l'esprit que Mocha et Chai peuvent être utilisés pour tester à peu près n'importe quel type de projet Node, qu'il s'agisse d'une bibliothèque, d'un outil de ligne de commande ou même d'un site Web. En utilisant les différentes options et plugins à votre disposition, vous devriez pouvoir satisfaire vos besoins de test assez facilement. Chacune de ces bibliothèques est très utile pour valider votre code et devrait être utilisée dans à peu près tous vos projets Node.

Espérons que cela a servi d'introduction utile à Moka et Chai. Il y a beaucoup plus à apprendre que ce que j'ai présenté ici, alors assurez-vous de consulter la documentation pour plus d'informations.

Horodatage:

Plus de Stackabuse