如何在nodejs中模拟请求和响应来testing中间件/控制器?

我的应用程序有几个层次:中间件,控制器,pipe理器。 控制器接口与中间件接口相同:(req,res,next)。

所以我的问题是:我怎样才能testing我的控制器,而无需启动服务器,并发送“真正的”请求本地主机。 我想要做的是创build请求,响应实例为nodejs然后只是调用controllers方法。

像这样的东西:

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

任何意见是高度赞赏。 谢谢!

PS我想这样做的原因是,最后我想testing响应对象是否包含玉视图的正确variables。

由于JavaScript是一种dynamictypes的语言,您可以创build模拟对象并将它们传递给您的控制器,如下所示:

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

如果您的控制器需要您的请求或响应对象中的特定数据或function,则需要在您的模拟中提供此类数据或function。 例如,

 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) 

node-mocks-http有一个半正式的实现

要求:

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

你可以编写req和response对象:

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

然后你可以直接testing你的控制器:

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

警告

在这个实现中写一个问题与事件发射器没有被解雇有关。

我会尝试使用dupertest 。 这是我创build的一个节点模块,用于简单控制器testing,而不必启动新的服务器。

它保留了像requestsupertest类这样的节点模块的熟悉语法,但是不需要启动服务器。

它像上面提到的Hector一样运行,但是与像Jasmine这样的testing框架相结合,感觉更加无缝。

有关您的问题的示例可能如下所示:

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

或者更明确的longhand版本:

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

注意:示例假设user_iduser是在某处定义的,并且控制器根据id获取并返回一个用户。

编辑:阅读你的回答上面的答案,我承认目前的缺点是,这个模块默认没有集成更强大的模拟请求或响应对象。 dupertest使得对reqres扩展和添加属性变得非常容易,但是默认情况下它们是相当裸露的。

如果你想使用真正的reqres对象,你必须发送真正的请求到服务器。 然而这比你想象的要容易得多。 在github快速回购中有很多例子。 以下显示了对req.route的testing

 var express = require('../') , request = require('./support/http'); describe('req', function(){ describe('.route', function(){ it('should be the executed Route', function(done){ var app = express(); app.get('/user/:id/edit', function(req, res){ // test your controllers with req,res here (like below) req.route.method.should.equal('get'); req.route.path.should.equal('/user/:id/edit'); res.end(); }); request(app) .get('/user/12/edit') .expect(200, done); }) }) }) 

有点旧post,但我想给我2分钱。 你想采取的方法取决于你是否正在做unit testing或集成testing。 如果你正在使用supertest的路线,这意味着你正在运行实际的代码,这意味着你正在进行集成testing。 如果这就是你想要做的这种方法是好的。

但是如果你正在进行unit testing,你可能会模拟req和res对象(以及其他依赖关系)。 在下面的代码(为简洁起见,删除了不相关的代码),我嘲笑res并给出了json方法的模拟实现,因为这是我testing所需的唯一方法。

 // SUT kids.index = function (req, res) { if (!req.user || !req.user._id) { res.json({ err: "Invalid request." }); } else { // non-relevent code } }; // Unit test var req, res, err, sentData; describe('index', function () { beforeEach(function () { res = { json: function (resp) { err = resp.err; sentData = resp.kids; } }; }); it("should return error if no user passed in request", function () { req = {}; kidsController.index(req, res); expect(err).to.equal("Invalid request."); }); /// More tests.... })