web-dev-qa-db-fra.com

Comment tester mon application express avec moka?

Je viens d'ajouter shouldjs et mocha à mon application express pour les tests, mais je me demande comment tester mon application. Je voudrais le faire comme ceci:

app = require '../app'
routes = require '../src/routes'

describe 'routes', ->
  describe '#show_create_user_screen', ->
    it 'should be a function', ->
      routes.show_create_user_screen.should.be.a.function
    it 'should return something cool', ->
      routes.show_create_user_screen().should.be.an.object

Bien sûr, le dernier test de cette suite de tests indique simplement à med que la fonction res.render (appelée dans show_create_user_screen) n'est pas définie, probablement parce que le serveur ne fonctionne pas et que la configuration n'a pas été effectuée. Je me demande donc comment les autres ont configuré leurs tests?

65

D'abord, bien que le test de votre code de routage soit quelque chose que vous pouvez ou non vouloir faire, en général, essayez de séparer votre logique métier intéressante en code javascript pur (classes ou fonctions) qui sont découplées de l'express ou du cadre que vous utilisez et utilisez des tests de vanille moka pour tester cela. Une fois que vous avez réalisé cela si vous voulez vraiment tester les routes que vous configurez dans mocha, vous devez passer mock req, res paramètres dans vos fonctions middleware pour imiter l'interface entre express/connect et votre middleware.

Pour un cas simple, vous pouvez créer un objet fictif res avec une fonction render qui ressemble à ceci.

describe 'routes', ->
  describe '#show_create_user_screen', ->
    it 'should be a function', ->
      routes.show_create_user_screen.should.be.a.function
    it 'should return something cool', ->
      mockReq = null
      mockRes =
        render: (viewName) ->
          viewName.should.exist
          viewName.should.match /createuser/

      routes.show_create_user_screen(mockReq, mockRes).should.be.an.object

De plus, les fonctions middleware FYI n'ont pas besoin de renvoyer de valeur particulière, c'est ce qu'elles font avec le req, res, next paramètres sur lesquels vous devez vous concentrer lors des tests.

Voici du JavaScript comme vous l'avez demandé dans les commentaires.

describe('routes', function() {
    describe('#show_create_user_screen', function() {
      it('should be a function', function() {
        routes.show_create_user_screen.should.be.a["function"];
      });
      it('should return something cool', function() {
        var mockReq = null;
        var mockRes = {
          render: function(viewName) {
            viewName.should.exist;
            viewName.should.match(/createuser/);
          }
        };
        routes.show_create_user_screen(mockReq, mockRes);
      });
    });
  });
32
Peter Lyons

trouvé une alternative dans suites de tests connect.js

Ils utilisent supertest pour tester une application de connexion sans lier le serveur à aucun port et sans utiliser de maquettes.

Voici un extrait de la suite de tests de middleware statique de connect (en utilisant mocha comme lanceur de test et supertest pour les assertions)

var connect = require('connect');

var app = connect();
app.use(connect.static(staticDirPath));

describe('connect.static()', function(){
  it('should serve static files', function(done){
    app.request()
    .get('/todo.txt')
    .expect('contents', done);
  })
});

Cela fonctionne également pour les applications express

64

Vous pouvez essayer SuperTest, puis le démarrage et l'arrêt du serveur sont pris en charge:

var request = require('supertest')
  , app     = require('./anExpressServer').app
  , assert  = require("assert");

describe('POST /', function(){
  it('should fail bad img_uri', function(done){
    request(app)
        .post('/')
        .send({
            'img_uri' : 'foobar'
        })
        .expect(500)
        .end(function(err, res){
            done();
        })
  })
});
21
LeeGee

mocha est fourni avec before, beforeEach, after et afterEach pour les tests bdd. Dans ce cas, vous devez utiliser avant dans votre description d'appel.

describe 'routes' ->
  before (done) ->
    app.listen(3000)
    app.on('connection', done)
6
fent

J'ai trouvé qu'il est plus facile de configurer une classe TestServer à utiliser en tant qu'assistant, ainsi qu'un client http d'assistance, et de faire de vraies demandes à un vrai serveur http. Il peut y avoir des cas où vous souhaitez vous moquer et écraser ces choses à la place.

// Test file
var http = require('the/below/code');

describe('my_controller', function() {
    var server;

    before(function() {
        var router = require('path/to/some/router');
        server = http.server.create(router);
        server.start();
    });

    after(function() {
        server.stop();
    });

    describe("GET /foo", function() {
        it('returns something', function(done) {
            http.client.get('/foo', function(err, res) {
                // assertions
                done();
            });
        });
    });
});


// Test helper file
var express    = require('express');
var http       = require('http');

// These could be args passed into TestServer, or settings from somewhere.
var TEST_Host  = 'localhost';
var TEST_PORT  = 9876;

function TestServer(args) {
    var self = this;
    var express = require('express');
    self.router = args.router;
    self.server = express.createServer();
    self.server.use(express.bodyParser());
    self.server.use(self.router);
}

TestServer.prototype.start = function() {
    var self = this;
    if (self.server) {
        self.server.listen(TEST_PORT, TEST_Host);
    } else {
        throw new Error('Server not found');
    }
};

TestServer.prototype.stop = function() {
    var self = this;
    self.server.close();
};

// you would likely want this in another file, and include similar 
// functions for post, put, delete, etc.
function http_get(Host, port, url, cb) {
    var options = {
        Host: Host,
        port: port,
        path: url,
        method: 'GET'
    };
    var ret = false;
    var req = http.request(options, function(res) {
        var buffer = '';
        res.on('data', function(data) {
            buffer += data;
        });
        res.on('end',function(){
            cb(null,buffer);
        });
    });
    req.end();
    req.on('error', function(e) {
        if (!ret) {
            cb(e, null);
        }
    });
}

var client = {
    get: function(url, cb) {
        http_get(TEST_Host, TEST_PORT, url, cb);
    }
};

var http = {
    server: {
        create: function(router) {
            return new TestServer({router: router});
        }
    },

    client: client
};
module.exports = http;
5
Bryan Donovan