如何在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,而不必启动新的服务器。
它保留了像request
或supertest
类这样的节点模块的熟悉语法,但是不需要启动服务器。
它像上面提到的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_id
和user
是在某处定义的,并且控制器根据id获取并返回一个用户。
编辑:阅读你的回答上面的答案,我承认目前的缺点是,这个模块默认没有集成更强大的模拟请求或响应对象。 dupertest
使得对req
和res
扩展和添加属性变得非常容易,但是默认情况下它们是相当裸露的。
如果你想使用真正的req
和res
对象,你必须发送真正的请求到服务器。 然而这比你想象的要容易得多。 在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.... })