这是一个关于使用Mocha在Sails JS中进行异步测试的问题。
我正在使用supertest库在Sails JS中编写控制器测试。我想检查是否在HTTP POST上调用了一个方法给我们的控制器。为此,我正在对该方法进行存根,并期望在end()
中调用它,如下所示:
request(sails.hooks.http.app)
.post('heartbeat/create')
.send('device: 1')
.end(function(err, res) {
expect(publishCreateStub.called).to.be.true;
done();
});
当我运行它时,期望失败,因为断言时不调用该方法。但是当我把期望放在setTimeout
如下时,它的作用是:
request(sails.hooks.http.app)
.post('heartbeat/create')
.send('device: 1')
.end(function(err, res) {
setTimeOut(function() {
expect(publishCreateStub.called).to.be.true;
done();
}, 1000);
});
有没有办法让测试通过setTimeout
?
以下是我正在测试的代码部分:HeartbeatController#create
您还可以通过发送拉取请求来帮助我们解决问题:https://github.com/multunus/one-mdm/issues/1
答案 0 :(得分:3)
实际问题是您的控制器不会等待publishCreate
被调用。因此,您正在使用201 Created
进行回复,而不检查是否已创建任何内容。
Heartbeat.findOne
或Heartbeat.publishCreate
可能会失败,但您会更新。
要解决此问题,您应该修改控制器,在Heartbeat
承诺回调中移动响应部分:
create: function (req, res, next) {
if(req.isSocket) {
Heartbeat.watch(req);
}
Heartbeat.create(req.body)
.exec(function(error, heartbeat) {
if(error) {
res.status(422);
return res.send('Invalid heartbeat data');
}
Heartbeat.findOne(heartbeat.id).populate('device').then(function(newHeartbeat) {
Heartbeat.publishCreate(newHeartbeat.device);
}).then(function() {
// success
res.status(201);
res.json({
device: heartbeat.device
});
}, function(err) {
// something bad happened
next(err);
});
});
}
在我的示例中,我将实际的错误处理委托给下一个快速错误处理中间件:
next(err);
但您可能决定自己处理错误,例如:
res.status(400);
res.send('Can not publish Heartbeat create');
答案 1 :(得分:1)
您的问题不在您的测试中,而是在您的应用程序中:
Heartbeat.create(req.body)
.exec(function(error, heartbeat) {
if(error) {
res.status(422);
return res.send('Invalid heartbeat data');
}
Heartbeat.findOne(heartbeat.id).populate('device').then(function(newHeartbeat) {
Heartbeat.publishCreate(newHeartbeat.device);
});
res.status(201);
return res.json({
device: heartbeat.device
});
});
}
https://github.com/multunus/one-mdm/blob/master/api/controllers/HeartbeatController.js
在这里,您正在创建一个承诺,但不会返回该承诺。所以在继续之前你无法等待承诺得到满足(或错误)。
在不详细了解您的应用程序的情况下,我不确定该修复程序。我会考虑将中间的位抽象为服务*,然后您的HeartbeatController
测试可以检查服务是否被调用(同步),并且您对该服务的测试可以执行使用该承诺的异步部分。
*更新:通过“服务”,我的意思是将其从HTTP的任何问题中抽象出来,因此它不知道请求或响应对象。最终结果是您已经从管理Heartbeat对象的部分解开了HTTP部分(控制器)。这使得两个部件更容易进行单元测试。