如何在 nodejs 中模拟请求和响应以测试中间件/控制器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14487809/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to mock request and response in nodejs to test middleware/controllers?
提问by potomok
My application has several layers: middleware, controllers, managers. Controllers interface is identical to middlewares one: (req, res, next).
我的应用程序有几个层:中间件、控制器、管理器。控制器接口与中间件一相同:(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.
所以我的问题是:如何在不启动服务器并向本地主机发送“真实”请求的情况下测试我的控制器。我想要做的是像 nodejs 一样创建请求、响应实例,然后调用控制器方法。
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.
PS我之所以要这样做,是因为最后我想测试响应对象是否包含正确的玉石视图变量。
回答by superluminary
There's a semi decent implementation at node-mocks-http
node-mocks-http有一个半体面的实现
Require it:
要求:
var mocks = require('node-mocks-http');
you can then compose req and response objects:
然后你可以组合 req 和 response 对象:
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.
在编写此实现中的问题时,有一个与事件发射器未被触发有关的问题。
回答by Hector Correa
Since JavaScript is a dynamically typed language you can create mock objects and passing them to your controllers as follow:
由于 JavaScript 是一种动态类型语言,您可以创建模拟对象并将它们传递给您的控制器,如下所示:
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)
回答by tydotg
I would try using dupertestfor this. It's a node module I created for the very purpose of easy controller testing without having to spin up a new server.
我会尝试为此使用dupertest。这是我创建的一个节点模块,其目的是轻松进行控制器测试,而无需启动新服务器。
It keeps the familiar syntax of node modules like requestor supertest, but again, without the need to spin up a server.
它保留了节点模块的熟悉语法,如requestor supertest,但同样,无需启动服务器。
It runs a lot like Hector suggested above, but integrates with a test framework like Jasmine to feel a little more seamless.
它的运行方式与上面建议的 Hector 非常相似,但与 Jasmine 等测试框架集成在一起,感觉更加无缝。
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_idand userare defined somewhere, and that the controller grabs and returns a user based on id.
注意:示例假设user_id和user定义在某处,并且控制器根据 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. dupertestmakes it super easy to extend and add properties to both reqand res, but by default they are pretty bare.
编辑:阅读您对上述答案的回复,我承认目前的缺点是该模块默认情况下没有集成更强大的模拟请求或响应对象。dupertest使得超级易于扩展和添加属性既req和res,但默认情况下,他们是相当光秃秃的。
回答by Abhishek Jain
A bit old post, but I would like to give my 2 cents. The approach you want to take depends on whether you are doing unit testing or integration testing. If you are going down the route of using supertest, that means you are running the actual implementation code and that means you are doing integration testing. If that's what you want to do this approach is fine.
有点旧的帖子,但我想给我的 2 美分。您想要采用的方法取决于您是在进行单元测试还是集成测试。如果您沿着使用 supertest 的路线走下去,那意味着您正在运行实际的实现代码,这意味着您正在进行集成测试。如果这就是你想要做的,这种方法很好。
But if you are doing unit testing, you would mock req and res objects (and any other dependencies involved). In the below code (non-relevant code removed for brevity), I am mocking res and giving just a mock implementation of json method, as that's the only method I need for my tests.
但是如果你在做单元测试,你会模拟 req 和 res 对象(以及任何其他涉及的依赖项)。在下面的代码中(为简洁起见,删除了不相关的代码),我正在模拟 res 并仅提供 json 方法的模拟实现,因为这是我测试所需的唯一方法。
// 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....
})
回答by zemirco
If you want to use the real reqand resobjects, you have to send real requests to the server. However this is much easier than you might think. There are a lot of examples at the express github repo. The following shows the tests for req.route
如果要使用真实req和res对象,则必须向服务器发送真实请求。然而,这比您想象的要容易得多。express github repo中有很多示例。下面显示了测试req.route
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);
})
})
})
回答by vincent
Take a look at node-tddand the useNockflag. It builds on top of mocha and nock and automatically creates and uses a recording file for each test.
看看node-tdd和useNock标志。它建立在 mocha 和 nock 之上,并为每个测试自动创建和使用记录文件。
We love that it's so easy to use. Basically just "enable and forget" and focus on writing requests / test cases. If requests for a test change, one still needs to delete or adjust the recording file, but at least it's entirely separate from the code.
我们喜欢它如此易于使用。基本上只是“启用和忘记”并专注于编写请求/测试用例。如果请求测试更改,仍然需要删除或调整录制文件,但至少它与代码完全分开。

