简体   繁体   English

用 Sinon 构建 Mongoose 模型

[英]Stubbing a Mongoose model with Sinon

I want to create a stub for the Mongoose save method in a particular model, so that any instance of my model I create will call the stub instead of the normal Mongoose save method.我想在特定模型中为 Mongoose save方法创建一个存根,以便我创建的模型的任何实例都将调用存根而不是普通的 Mongoose save方法。 My understanding is that the only way to do this is to stub the entire model like this:我的理解是,唯一的方法是像这样存根整个模型:

var stub = sinon.stub(myModel.prototype);

Unfortunately, this line of code causes my tests to throw the following error:不幸的是,这行代码导致我的测试抛出以下错误:

TypeError: Cannot read property 'states' of undefined

Does anyone know what is going wrong here?有谁知道这里出了什么问题?

There are two ways to accomplish this.有两种方法可以做到这一点。 The first is第一个是

var mongoose = require('mongoose');
var myStub = sinon.stub(mongoose.Model, METHODNAME);

If you console log mongoose.Model you will see the methods available to the model (notably this does not include lte option).如果你控制台日志 mongoose.Model 你会看到模型可用的方法(值得注意的是这不包括 lte 选项)。

The other (model specific) way is另一种(特定于模型)方式是

var myStub = sinon.stub(YOURMODEL.prototype.base.Model, 'METHODNAME');

Again, the same methods are available to stub.同样,相同的方法可用于存根。

EDIT: Some methods such as save are stubbed as follows:编辑:保存等一些方法存根如下:

var myStub = sinon.stub(mongoose.Model.prototype, METHODNAME);
var myStub = sinon.stub(YOURMODEL.prototype, METHODNAME);

Take a look to sinon-mongoose .看看sinon-mongoose You can expects chained methods with just a few lines:您只需几行就可以期待链式方法:

sinon.mock(YourModel).expects('find')
  .chain('limit').withArgs(10)
  .chain('exec');

You can find working examples on the repo.您可以在 repo 上找到工作示例。

Also, a recommendation: use mock method instead of stub , that will check the method really exists.另外,建议:使用mock方法而不是stub ,这将检查该方法是否确实存在。

save is not a method on the model, it's a method on the document (instance of a model). save不是模型上的方法,它是文档(模型实例)上的方法。 Stated here in mongoose docs .在 mongoose 文档中说明。

Constructing documents构建文件

Documents are instances of our model.文档是我们模型的实例。 Creating them and saving to the database is easy创建它们并保存到数据库很容易

Therefore, it will always be undefined if you're using your model to mock a save()因此,如果您使用模型模拟save() ,它将始终是未定义的

Going along with @Gon's answer, using sinon-mongoose & factory-girl with Account being my model:与@Gon 的回答一致,使用sinon-mongoosefactory-girlAccount是我的模型:

Will not work不管用

var AccountMock = sinon.mock(Account)

AccountMock
  .expects('save') // TypeError: Attempted to wrap undefined property save as function
  .resolves(account)

Will work工作

var account = { email: 'sasha@gmail.com', password: 'abc123' }

Factory.define(account, Account)
Factory.build('account', account).then(accountDocument => {
  account = accountDocument

  var accountMock = sinon.mock(account)

  accountMock
    .expects('save')
    .resolves(account)

  // do your testing...
})

Instead of the whole object, try:而不是整个对象,尝试:

sinon.stub(YOURMODEL.prototype, 'save')

Make sure YOURMODEL is the class not the instance.确保 YOURMODEL 是类而不是实例。

Tangentially-related, but relevant...切线相关,但相关...

I needed to mock a custom model method like:我需要模拟一个自定义模型方法,例如:

myModelSchema.methods.myCustomMethod = function() {....}

To create a stub I did:要创建一个存根,我做了:

myCustomMethodStub = sinon.stub(MyModel.schema.methods, 'myCustomMethod').callThrough();

As told by djv, the save method is on the document.正如 djv 所说, save方法在文档上。 So you can stub it this way:所以你可以这样存根:

const user = new User({
      email: 'email@email.com',
      firstName: 'firstName',
      lastName: 'lastName',
      userName: 'userName',
      password: 'password',
    });

stub(user, 'save').resolves({ foo: 'bar' });

Bonus, you can assert it with Chai and Chai as promised this way:奖金,您可以按照承诺的方式使用Chai和 Chai 声明它:

const promise = user.save();
await chai.assert.doesNotBecome(promise, { foo: 'bar' });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM