Test delle unità in node.js e moduli di simulazione

2

Sto provando a testare questo wrapper alla richiesta che ho fatto:

// lib/http-client.js
var app = require('app'),
    request = require('request');

exports.search = function(searchTerm, next) {
  var options = {
    url: 'https://api.datamarket.azure.com/Bing/Search/Web',
    qs: {
      'Query': '\'' + searchTerm + '\'',
      'Adult': '\'Off\'',
      '$format': 'json',
      '$top': 10
    },
    auth: {
      user: app.get('bing identifier'),
      pass: app.get('bing identifier')
    }
  };

  request(options, function(err, res, body){

    if (err) return next(err);
    // TODO: parse JSON and return results
  });
};

dove app è un'istanza di espresso . La domanda è: come posso testare la funzione di questo "modulo" senza dover toccare Internet? Se dovessi farlo in altre lingue avrei preso in giro il modulo di richiesta ma non so se questo è il modo migliore di farlo in node.js.

// NODE_PATH=lib

describe('Http Client', function(){
  it('should return error if transport failed', function(){
    var c = require('http-client'),
        results = 'foo';
    // request mock should return results when called
    c.search('foo', function(err, results){
      results.should.eql(res);
    });
    // TODO
  });
  it('should return an error if JSON parsing failed', function(){
    // TODO
  });
  it('should return results', function(){
    // TODO
  });
});
    
posta Jürgen Paul 25.07.2013 - 05:55
fonte

2 risposte

2

Se il tuo modulo ha un costruttore che accetta l'app e richiede come argomenti del costruttore (in altre parole l'integrazione delle dipendenze), puoi semplicemente fornire un'implementazione di richiesta stoppia / derisa nel test.
In caso contrario: so che è possibile ignorare nei test ciò che RequireJS restituisce quando si richiede qualcosa, quindi suppongo che lo stesso sarebbe possibile in node.js. Pertanto, se è possibile modificare la configurazione del caricatore di moduli in un test, è possibile configurarlo per restituire un'implementazione di richiesta con stucco / derisione.
Personalmente, farei il percorso di iniezione delle dipendenze. Dover configurare il modulo loader nei test è un fastidio sul retro ...

    
risposta data 25.07.2013 - 09:01
fonte
0

L'ho fatto di recente. Hai dimenticato dove ho letto ma è piuttosto facile.

Ecco le basi del mio codice.

var express = require('express');
var http    = require('http');

var MyServer = function(options) {
  var app = express();
  app.get(/^\/foo.html/, sendFoo);
  app.get(/^\/bar.html/, sendBar);
  var server = options.server || http.createServer(app);
  server.listen(options.port);

  function sendFoo(req, res) {
     res.writeHead(200);
     res.write("foo");
     res.end();
  }

  function sendBar(req, res) {
     res.writeHead(200);
     res.write("bar");
     res.end();
  }

  this.close = function() {
     server.close();
  }
};

Come puoi vedere sul mio server sia http.createServer che quello che ho passato. Forse dovrei sempre passarlo? Ma in ogni caso. Ho creato un server fittizio

var events = require('events');

var MockHTTPServer = function() {
  var eventEmitter = new events.EventEmitter();
  var self = this;

  this.once = eventEmitter.once.bind(eventEmitter);

  this.listen = function() {
    eventEmitter.emit('listening', self, 0);
  };

  this.close = function() {
  };
};

E a MockResponse

var MockResponse = function(callback) {
  this.headers = {};
  this.statusCode = -1;
  this.body = undefined;

  this.setHeader = function(key, value) {
    this.headers[key] = value;
  }.bind(this);

  this.writeHead = function(statusCode, headers) {
    this.statusCode = statusCode;
    Object.keys(headers).forEach(function(key) {
      this.headers[key] = headers[key];
    }.bind(this));
  }.bind(this);

  this.write = function(data, encoding) {
    this.body = data.toString(encoding);
  }.bind(this);

  this.end = function() {
    var fn = callback;
    callback = undefined;
    fn(this);
  }.bind(this);
};

Nota che questa non è una risposta completa. L'ho appena provato nei miei test e ho aggiunto solo le funzioni che sono state chiamate.

Per testare effettivamente ho creato un server di test

var Promise = require('promise');

var TestServer = function(callback) {
  var server = new MyServer({
    server: new MockHTTPServer,
  }, callback);

  this.close = function() {
    server.close();
  };

  var request = function(req, callback) {
    var res = new MockResponse(callback);
    server.handleRequest(req, res);
  };

  var getP = function(url) {
    return new Promise(function(resolve, reject) {
      request({ url: url, method: 'GET'}, resolve);
    });
  };

  this.getP = getP;
  this.request = request;
};

Che, usando la moka, posso testare così

describe('test server', function() {

  var server;

  before(function(done) {
    server = new TestServer(done);
  });

  describe('test', function() {
    it('serves bar', function(done) {
      server.getP("http://localhost/bar.html").then(function(res) {
        res.body.should.containEql("bar");
      }).then(done, done);
    });

    it('serves foo', function(done) {
      server.getP("http://localhost/foo.html").then(function(res) {
        res.body.should.containEql("foo");
      }).then(done, done);
    });
  });

  after(function(done) {
    server.close();
    done();
  });

});

Puoi vedere che ho appena creato gli oggetti richiesta al volo

    
risposta data 03.10.2014 - 23:57
fonte

Leggi altre domande sui tag