Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock request and response in nodejs to test middleware/controllers?

My application has several layers: middleware, controllers, managers. Controllers interface is identical to middlewares one: (req, res, next).

So my question is: how can I test my controllers without starting the server and sending 'real' requests to localhost. What I want to do is to create request, response instances as nodejs does and then just call controllers method.

Something like this:

var req = new Request()
var res = new Response()
var next = function(err) {console.log('lala')}
controller.get_user(req, res, next)

Any advice is highly appreciated. Thanks!

P.S. the reason why I want to do this is that at the end I would like to test whether the response object contains correct variables for the jade views.

like image 503
potomok Avatar asked Jan 23 '13 19:01

potomok


People also ask

How do you mock in node JS?

In Jest, Node. js modules are automatically mocked in your tests when you place the mock files in a __mocks__ folder that's next to the node_modules folder. For example, if you a file called __mock__/fs. js , then every time the fs module is called in your test, Jest will automatically use the mocks.


3 Answers

There's a semi decent implementation at node-mocks-http

Require it:

var mocks = require('node-mocks-http'); 

you can then compose req and response objects:

req = mocks.createRequest(); res = mocks.createResponse(); 

You can then test your controller directly:

var demoController = require('demoController'); demoController.login(req, res);  assert.equal(res.json, {}) 

caveat

There is at time of writing an issue in this implementation to do with the event emitter not being fired.

like image 62
superluminary Avatar answered Oct 04 '22 06:10

superluminary


Since JavaScript is a dynamically typed language you can create mock objects and passing them to your controllers as follow:

var req = {}; var res = {}; var next = function(err) {console.log('lala')} controller.get_user(req, res, next) 

If your controller needs a particular piece of data or functionality from your request or response object you'll need to provide such data or functionality in your mocks. For example,

var req = {}; req.url = "http://google.com"; // fake the Url  var res = {}; res.write = function(chunk, encoding) {    // fake the write method  };  var next = function(err) {console.log('lala')} controller.get_user(req, res, next) 
like image 23
Hector Correa Avatar answered Oct 04 '22 05:10

Hector Correa


I would try using dupertest for this. It's a node module I created for the very purpose of easy controller testing without having to spin up a new server.

It keeps the familiar syntax of node modules like request or supertest, but again, without the need to spin up a server.

It runs a lot like Hector suggested above, but integrates with a test framework like Jasmine to feel a little more seamless.

An example relating to your question may look like:

request(controller.get_user)
  .params({id: user_id})
  .expect(user, done);

Or the more explicit longhand version:

request(controller.get_user)
  .params({id: user_id})
  .end(function(response) {
    expect(response).toEqual(user);
    done();
  });

Note: the examples assume user_id and user are defined somewhere, and that the controller grabs and returns a user based on id.

Edit: reading your response to an answer above, I will admit the downside currently is that this module does not integrate a more robust mock request or response object by default. dupertest makes it super easy to extend and add properties to both req and res, but by default they are pretty bare.

like image 31
tydotg Avatar answered Oct 04 '22 04:10

tydotg