2

I'm trying to test this wrapper to request that I made:

// 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
  });
};

where app is an instance of express. The question is, how do I test the function of this "module" without having to touch the internet? If I was to do this in other languages I would have mocked the request module but I don't know if that's the best way to do it 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
  });
});
2

If your module has a constructor that takes the app and request as constructor arguments (in other words dependency injection), you can just provided a stubbed/mocked implementation of request in your test.
If not: I know you can override in tests what RequireJS returns when requiring something, so I would assume the same would be possible in node.js. So if you can change the configuration of the module loader in a test, you can configure it to return a stubbed/mocked implementation of request.
Personally, I'd go the dependency injection route. Having to configure your module loader in tests is a pain in the backside...

0

I recently did this. Forgot where I read about it but it's pretty easy.

Here's the basics of my code.

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();
  }
};

As you can see my server either users http.createServer or the one I pass in. Maybe I should always pass it in? But in any case. I made a mock server

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() {
  };
};

And 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);
};

Note this is not a complete response mock. I just tried it in my tests and only added the functions that were called.

To actually test I made a test server

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;
};

Which, using mocha, I can test like this

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();
  });

});

You can see I just make up request objects on the fly

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.