问题
I have a restify action code block below:
function retriveAll(req, res, next) {
db.user
.find({where: {id: 1})
.then(function(user){
res.send(user);
})
.catch(function(details){
res.send(details.message);
})
.finally(function(){
next();
});
}
I want to test this action specifically validating that res.send() was called within this code block. And later on validating the res.send() returned data. I'm using SinonJs and Mocha for testing framework. Here's a sample test code block for the method above.
describe('retrieveAll()', function() {
reqStub = {};
resStub = {send: sinon.stub()};
nextStub = sinon.stub();
beforeEach(function() {
module.retrieveAll(reqStub, resStub, nextStub);
});
// this doesn't work
// and the sub.calledCount is 0
// i wonder if it's because the res.send() is inside a Promise code block???
// if I move the res.send() out from Promise, just before next(), then it works
it('should call res.send()', function() {
sinon.assert.calledOnce(resStub.send);
});
// this one works
it('should call next', function() {
sinon.assert.calledOnce(nextStub);
});
});
Could someone shed some light?
回答1:
The beforeEach()
's callback function receives a done
parameter that can be called to signal an asynchronous completion. Since your retriveAll
function calls the last parameter (next
) as the last action, you can pass that parameter as the next
value and it should work:
beforeEach(function(done) {
module.retrieveAll(reqStub, resStub, done);
});
You will however loose the nextStub
, so... alternatively, you could spy on that done
function:
describe('retrieveAll()', function() {
var reqStub = {};
var resStub = {send: sinon.stub()};
var nextSpy;
beforeEach(function(done) {
nextSpy = sinon.spy(done);
module.retrieveAll(reqStub, resStub, done);
});
// this doesn't work
// and the sub.calledCount is 0
// i wonder if it's because the res.send() is inside a Promise code block???
// if I move the res.send() out from Promise, just before next(), then it works
it('should call res.send()', function() {
sinon.assert.calledOnce(resStub.send);
});
// this one works
it('should call next', function() {
sinon.assert.calledOnce(nextSpy);
});
});
回答2:
So, I got this working thanks for @Amit for pointing me to the done
callback on beforeEach
First, I modified the retrieveAll
so the next
callback is included in the promise chain. I put it in the finally
handler making sure that next
will be called after all process.
Second, I passed the done
to beforeEach
and then nextStub
will spy on done
callback.
Third, instead of passing done
cb to module.v1.retrieveAll
I used nextStub
. This solve the issue on testing nextStub.calledOnce
.
The updated code now looks:
function retriveAll(req, res, next) {
db.user
.find({where: {id: 1})
.then(function(user){
res.send(user);
})
.catch(function(details){
res.send(details.message);
})
.finally(function(){
next();
});
}
describe('retrieveAll()', function() {
var reqStub = {};
var resStub = {send: sinon.stub()};
var nextStub;
beforeEach(function(done) {
nextStub = sinon.spy(done);
module.retrieveAll(reqStub, resStub, nextStub);
});
// this doesn't work
// and the sub.calledCount is 0
// i wonder if it's because the res.send() is inside a Promise code block???
// if I move the res.send() out from Promise, just before next(), then it works
it('should call res.send()', function() {
sinon.assert.calledOnce(resStub.send);
});
// this one works
it('should call next', function() {
sinon.assert.calledOnce(nextStub);
});
});
I going to choose @Amit answer as best answer since he helped and gave me clues on the changes.
来源:https://stackoverflow.com/questions/32340667/testing-restify-route-handler-that-contains-promise-code-block-using-sinonjs-an