我正在测试一个使用mongoose的快速路由处理程序。 我的路由处理程序代码如下。
// Require models.
var Comment = require('../models/commentModel');
var User = require('../models/userModel');
var Post = require('../models/postModel');
// Require mongoose and set bluebird to handle its promises.
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
// Creates a comment.
exports.create_comment = function(req, res) {
var comment = new Comment();
return comment.save().then(function(createdComment) {
res.json(createdComment);
var promises = [
User.findById(userId).exec(),
Post.findById(postId).exec()
];
// Should resolve to [{ user: {/* */} }, { post: {/* */} }]
var promisedDocs = Promise.all(promises);
// Function provided to Array.map().
function pushAndSave(obj) {
// Extract the doc from { doc: {/* */} }
var doc = obj[Object.keys(obj)[0];
doc.comments.push(createdComment);
return doc.save();
}
// Return promise and process the docs returned by resolved promise.
return promisedDocs.then(function(results) {
results.map(pushAndSave);
});
})
.catch(function(err) {
res.json(err);
});
}
我试图测试的逻辑是,当一切正常时,会调用相应的函数。基本上,我期待以下内容:
要调用comment.save()
,User.findById().exec()
,Post.findById().exec()
,user.save()
和post.save()
。
为了测试这个,我使用的是mocha,chai,sinon,sinon-mongoose,sinon-stub-promise和node-mocks-http。 这是我的测试(我正在考虑设置)。
it('Makes all the appropriate calls when everyting goes right', function() {
// Mock through sinon-mongoose
var userMock = sinon.mock(User);
var postMock = sinon.mock(Post);
userMock
.expects('findById')
.chain('exec')
.resolves({
user: {/**/}
});
postMock
.expects('findById')
.chain('exec')
.resolves({
post: {/**/}
});
// Stubbing calls to Model#save.
var saveComment = sinon.stub(Comment.prototype, 'save');
var saveUser = sinon.stub(User.prototype, 'save');
var savePost = sinon.stub(Post.prototype, 'save');
saveComment.returnsPromise().resolves({
comment: {/**/}
});
saveUser.returnsPromise().resolves({
user: {/**/}
});
savePost.returnsPromise().resolves({
post: {/**/}
});
// Mocking req and res with node-mocks-http
req = mockHttp.createRequest({
method: 'POST',
url: '/comments',
user: {/**/},
body: {/**/}
});
res = mockHttp.createResponse();
// Call the handler.
commentsController.create_comment(req, res);
expect(saveComment.called).to.equal(true); // Pass
userMock.verify(); // Pass
postMock.verify(); // Pass
expect(saveUser.called).to.equal(true); // Fail
expect(savePost.called).to.equal(true); // Fail
});
如您所见,未调用user.save()
和post.save()
。这可能是我的Promise.all()
设置和后续处理或我的测试本身的问题,但我没有想法。
你能发现我的错误吗?
先谢谢你们。
答案 0 :(得分:2)
重新创建示例中缺少的部分比实际找到问题花了我更长的时间。您可以在下面找到测试方案的固定版本。
var mongoose = require('mongoose');
module.exports = mongoose.model('User', {
name: String,
comments: Array
});
var mongoose = require('mongoose');
module.exports = mongoose.model('Post', {
name: String,
comments: Array
});
var mongoose = require('mongoose');
module.exports = mongoose.model('Comment', {
text: String
});
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
var Comment = require('./comment');
var User = require('./user');
var Post = require('./post');
// Creates a comment.
exports.create_comment = function (req, res) {
var comment = new Comment();
const userId = req.user.id;
const postId = req.body.id;
return comment.save().then(function (createdComment) {
res.json(createdComment);
var promises = [
User.findById(userId).exec(),
Post.findById(postId).exec()
];
// Should resolve to [{ user: {/* */} }, { post: {/* */} }]
var promisedDocs = Promise.all(promises);
// Function provided to Array.map().
function pushAndSave (doc) {
doc.comments.push(createdComment);
return doc.save();
}
// Return promise and process the docs returned by resolved promise.
return promisedDocs.then(function (results) {
results.map(pushAndSave);
});
})
.catch(function (err) {
console.error('foo', err);
res.json(err);
});
};
'use strict';
const chai = require('chai');
const sinon = require('sinon');
const SinonChai = require('sinon-chai');
var sinonStubPromise = require('sinon-stub-promise');
sinonStubPromise(sinon);
require('sinon-mongoose');
chai.use(SinonChai);
const expect = chai.expect;
var mockHttp = require('node-mocks-http');
const commentsController = require('./controller');
var Comment = require('./comment');
var User = require('./user');
var Post = require('./post');
describe.only('Test', () => {
it('Makes all the appropriate calls when everyting goes right',
function (done) {
// Mock through sinon-mongoose
var userMock = sinon.mock(User);
var postMock = sinon.mock(Post);
userMock
.expects('findById')
.chain('exec')
.resolves(new User());
postMock
.expects('findById')
.chain('exec')
.resolves(new Post());
// Stubbing calls to Model#save.
var saveComment = sinon.stub(Comment.prototype, 'save');
var saveUser = sinon.stub(User.prototype, 'save');
var savePost = sinon.stub(Post.prototype, 'save');
saveComment.resolves({
comment: { /**/}
});
saveUser.resolves({
user: { /**/}
});
savePost.resolves({
post: { /**/}
});
// Mocking req and res with node-mocks-http
const req = mockHttp.createRequest({
method: 'POST',
url: '/comments',
user: {id: '123'},
body: {id: 'xxx'}
});
const res = mockHttp.createResponse();
// Call the handler.
commentsController.create_comment(req, res).then(() => {
expect(saveComment.called).to.equal(true); // Pass
userMock.verify(); // Pass
postMock.verify(); // Pass
expect(saveUser.called).to.equal(true); // Fail
expect(savePost.called).to.equal(true); // Fail
done();
});
});
});
总的来说,断言逻辑在理论上是可以的。我发现的问题如下: