web-dev-qa-db-fra.com

Test unitaire des routes de routeur express

Je suis nouveau sur Node et Express et j'essaie de tester mes routes/contrôleurs. J'ai séparé mes routes de mes contrôleurs. Comment dois-je procéder pour tester mes routes?

config/express.js

  var app = express();
  // middleware, etc
  var router = require('../app/router')(app);

application/routeur/index.js

  module.exports = function(app) {
    app.use('/api/books', require('./routes/books'));
  };

application/routeur/routes/books.js

  var controller = require('../../api/controllers/books');
  var express = require('express');
  var router = express.Router();

  router.get('/', controller.index);

  module.exports = router;

app/api/controllers/books.js

// this is just an example controller
exports.index = function(req, res) {
    return res.status(200).json('ok');
};

application/tests/api/routes/books.test.js

  var chai = require('chai');
  var should = chai.should();
  var sinon = require('sinon');

  describe('BookRoute', function() {

  });
24
cusejuice

Code:

config/express.js

var app = express();
// middleware, etc
var router = require('../app/router')(app);

module.exports = app;

app/tests/api/routes/books.test.js

var chai = require('chai');
var should = chai.should();
var sinon = require('sinon');
var request = require('supertest');
var app = require('config/express');

describe('BookRoute', function() {
    request(app)
        .get('/api/books')
        .expect('Content-Type', /json/)
        .expect('Content-Length', '4')
        .expect(200, "ok")
        .end(function(err, res){
           if (err) throw err;
        });
});

Considérations:

Si votre serveur nécessite un état initial au début d'un ensemble de tests (parce que vous exécutez des appels qui mutent l'état du serveur), vous devrez écrire une fonction qui renverra une application fraîchement configurée et le début de chaque groupe de tests. Il existe une bibliothèque NPM: https://github.com/bahmutov/really-need qui vous permettra d'exiger une version fraîchement instanciée de votre serveur.

9
ironchefpython

C'est intéressant car vous avez séparé vos contrôleurs de vos routeurs. L'autre article de StackOverflow mentionné dans les commentaires est un bon moyen de tester vos contrôleurs, je pense. La chose à garder à l'esprit avec les tests unitaires est ce que vous testez exactement. Vous ne devriez pas avoir besoin d'écrire des tests pour tester la bibliothèque express, car elle a probablement ses propres tests unitaires. Il vous suffit donc de tester vos appels vers la bibliothèque. Donc, pour l'itinéraire des livres, il vous suffit de tester cette seule ligne de code:

router.get('/', controller.index);

J'ai regardé autour de moi pour voir s'il y avait un moyen évident d'obtenir une liste d'itinéraires à partir de la bibliothèque express, mais je n'en ai pas vu un. Vous pouvez probablement simplement regarder la bibliothèque elle-même et vérifier ses internes pour voir si vous définissez un itinéraire correctement. Une autre option est de le simuler et de vérifier que vous l'appelez correctement.

Cela va devenir assez compliqué car vous devez modéliser certaines parties fondamentales de Javascript afin de tester cette seule ligne de code. Voici comment je l'ai fait:

describe('BookRoute', function() {
  it("should route / to books controller index", function() {
    var controller = require('../../../api/controllers/books');
    var orig_this = this;
    var orig_load = require('module')._load;
    var router = jasmine.createSpyObj('Router', ['get']);
    var express = jasmine.createSpyObj('express', ['Router']);
    express.Router.and.returnValues(router);
    spyOn(require('module'), '_load').and.callFake(function() {
      if (arguments[0] == 'express') {
        return express;
      } else {
        return orig_load.apply(orig_this, arguments);
      }
    });
    require("../../../router/routes/books");
    expect(router.get).toHaveBeenCalledWith('/', controller.index);
  });
});

Ce qui se passe ici, c'est que j'ai utilisé la fonction spyOn de Jasmine pour espionner la fonction _load dans module.js, qui gère tous les appels requis. C'est ainsi que lorsque nous avons besoin du routeur de livres et qu'il appelle ('express') nous pouvons retourner notre SpyObj express que nous avons créé avec jasmine.createSpyObj. Une fois que nous avons remplacé express par notre objet espion, nous pouvons le faire retourner notre routeur SpyObj qui nous permettra d'espionner router.get. Ensuite, nous pouvons vérifier qu'il est appelé avec '/' et controller.index.

Cela pourrait probablement être transformé en une sorte d'utilitaire si vous vouliez beaucoup l'utiliser.

J'évite généralement beaucoup de ces choses en utilisant une approche plus orientée objet et soit je passe un objet partout où je peux me moquer pour les tests, soit vous pouvez utiliser une sorte d'injection de dépendance comme Angular = utilise.

5
Peter Haight

J'ai trouvé ce blog incroyablement perspicace lors du test de mes propres points de terminaison de serveurs.

Dans le blog, il aborde:

  • Comment utiliser la bibliothèque de test de point de terminaison supertest .

  • Comment faire tourner et démonter par programme un serveur express avec vos routes nécessaires avant et après chaque test de point final. (il explique également pourquoi vous voudriez faire cela).

  • Comment éviter un piège commun, nécessite la mise en cache de vos modules requis dans vos tests unitaires, ce qui entraîne des conséquences inattendues.

J'espère que cela t'aides. Bonne chance et si vous avez d'autres questions, faites-le moi savoir.

2
Patrick Motard