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