Unit testing Sinon Mock of Mongoose保存方法,用于模型的所有未来实例(带有承诺)

Unit testing Sinon Mock of Mongoose保存方法,用于模型的所有未来实例(带有承诺),unit-testing,mongoose,mocking,promise,sinon,Unit Testing,Mongoose,Mocking,Promise,Sinon,我试图在单元测试用例(Sinon、Mocha、Chai)中使用promises为特定模型的所有实例模拟Mongoose save方法。根据其他几个例子,我正在使用sinon mongoose和sinon。我试图达到测试代码的这种最终状态: var expect = require('chai').expect; var sinon = require('sinon'); require('sinon-as-promised'); require('sinon-mongoose'); /* M

我试图在单元测试用例(Sinon、Mocha、Chai)中使用promises为特定模型的所有实例模拟Mongoose save方法。根据其他几个例子,我正在使用sinon mongoose和sinon。我试图达到测试代码的这种最终状态:

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方法是一个每个实例的方法,因此上面的mock不能“全局”工作,也不能在被测试的被调用的addUser()方法中工作(addUser()不能看到mock并访问数据库)


是否有某种方法可以引用Schema对象或其他对象属性来模拟所有后续实例,而无需创建自定义对象包装器或使用其他深奥的方法?这篇SO帖子上的最后一个答案(不是标记答案)最接近,但它只适用于模型的特定实例:

我能够根据@Merott(Github)的建议开发一个解决方案,如以下关于sinon mongoose的问题讨论所述(尽管有一些关于操纵原型的讨论):

基本上,我必须在保存模拟之前添加以下代码,并使用模型原型:

Object.defineProperty(UserModel.prototype, 'save', {
  value: UserModel.prototype.save,
  configurable: true,
  });
上面的完整代码片段经过适当调整:

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();
});

我看到的唯一问题是post Mock.restore()。如果我想通过save()返回到正常的数据库调用,我在模拟还原()后看到了一些问题。由于我在模拟所有的数据库调用,这并不相关,但对于那些需要模拟和真实调用混合使用的人来说,这可能是一个问题。

我能够根据@Merott(Github)的建议开发一个解决方案,如以下针对sinon mongoose的问题讨论所述(尽管有一些关于操纵原型的讨论):

基本上,我必须在保存模拟之前添加以下代码,并使用模型原型:

Object.defineProperty(UserModel.prototype, 'save', {
  value: UserModel.prototype.save,
  configurable: true,
  });
上面的完整代码片段经过适当调整:

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();
});

我看到的唯一问题是post Mock.restore()。如果我想通过save()返回到正常的数据库调用,我会在post Mock restore()中看到一些问题。因为我正在模拟所有的数据库调用,这与此无关,但对于那些需要混合模拟和实际调用的人来说,这可能是一个问题

“因为我在模拟所有数据库调用,所以这并不相关,但对于那些需要模拟和真实调用混合的人来说,这可能是一个问题”。除非有人将单元/集成和e2e测试混合在一起,否则情况永远不会如此。”因为我模拟所有的数据库调用,所以这并不相关,但对于那些需要模拟和真实调用混合的人来说,这可能是一个问题”。除非有人将单元/集成和e2e测试混合在一起,否则这种情况永远不会发生。