未来所有模型实例的 Mongoose Save 方法的Sinon Mock(带有承诺)
Posted
技术标签:
【中文标题】未来所有模型实例的 Mongoose Save 方法的Sinon Mock(带有承诺)【英文标题】:Sinon Mock of Mongoose Save method for all future instances of a Model (with promises) 【发布时间】:2017-04-19 04:18:24 【问题描述】:我正在尝试使用 Promise 在单元测试用例(Sinon、Mocha、Chai)期间为特定模型的所有实例模拟 Mongoose 保存方法。根据其他几个示例,我正在使用 sinon-mongoose 和 sinon-as-promised。我正在尝试达到类似测试代码的这种最终状态:
var expect = require('chai').expect;
var sinon = require('sinon');
require('sinon-as-promised');
require('sinon-mongoose');
/* Mongoose schema+model for User method persist */
var UserModel = require('./models').userModel;
/* code module that will be tested */
var userMethods = require('./user');
/* unit test setup*/
var userModelMock = sinon.mock(UserModel);
/* mock all instances of UserModel saves with a forced error return to test code modules */
userModelMock.expects('save')
.chain('exec')
.rejects('error saving');
/* call code module method for testing that creates new instance of UserModel and receives mocked save error*/
return userMethods.addUser().then(function(result)
expect(result).to.equal(false);
userModelMock.restore();
);
我意识到 save 方法是每个实例的方法,因此上述模拟不能“全局”工作或在被测调用的 addUser() 方法中工作(addUser() 看不到模拟并命中数据库)。
是否有某种方法可以引用 Schema 对象或其他对象属性来模拟所有后续实例,而无需创建自定义对象包装器或使用其他深奥的方法?此 SO 帖子的最后一个答案(不是标记的答案)最接近,但它仅适用于模型的特定实例:Stubbing a Mongoose model using Sinon
【问题讨论】:
【参考方案1】:我能够根据@Merott (Github) 的建议开发解决方案,如以下针对 sinon-mongoose 的问题讨论中所述(尽管有一些关于操纵原型的讨论):https://github.com/underscopeio/sinon-mongoose/issues/7
基本上我必须在保存模拟之前添加以下代码并处理模型原型:
Object.defineProperty(UserModel.prototype, 'save',
value: UserModel.prototype.save,
configurable: true,
);
上面有适当调整的完整代码sn-p:
var expect = require('chai').expect;
var sinon = require('sinon');
require('sinon-as-promised');
require('sinon-mongoose');
/* Mongoose schema+model for User method persist */
var UserModel = require('./models').userModel;
/* code module that will be tested */
var userMethods = require('./user');
/* unit test setup*/
Object.defineProperty(UserModel.prototype, 'save',
value: UserModel.prototype.save,
configurable: true,
);
var userModelMock = sinon.mock(UserModel.prototype);
/* mock all instances of UserModel saves with a forced error return to test code modules */
userModelMock.expects('save')
.chain('exec')
.rejects('error saving');
/* call code module method for testing that creates new instance of UserModel and receives mocked save error*/
return userMethods.addUser().then(function(result)
expect(result).to.equal(false);
userModelMock.restore();
);
我看到的唯一问题是发布 Mock.restore()。如果我想通过 save() 返回正常的数据库调用,我在 mock restore() 后看到了一些问题。由于我正在模拟我所有的数据库调用,因此它并不相关,但对于那些需要混合模拟和真实调用的人来说可能是一个问题。
【讨论】:
“因为我在模拟我所有的数据库调用,所以它不相关,但对于那些需要混合模拟和真实调用的人来说,这可能是一个问题”。除非有人将单元/集成和 e2e 测试混为一谈,否则永远不会出现这种情况。以上是关于未来所有模型实例的 Mongoose Save 方法的Sinon Mock(带有承诺)的主要内容,如果未能解决你的问题,请参考以下文章
当嵌入式数组对象更改时,Mongoose 实例 .save() 不起作用
无法使用 mongoose Model.save() 保存 - 给出内部服务器错误