首页 > 解决方案 > 如何为带有 sinon 的函数传递假参数并期望指定的返回值

问题描述

我有两个功能,一个取决于另一个

所以例子这就是我关心的类中函数的样子,User.findOne()并且user.update()

const Models = require('../models');
const { User } = Models;

class UserService {
  async updateUser(data) {
    const { id } = data;
    const user = await User.findOne({ where: { id } })
    if (user) {
      return await user.update(data)
    }
    return null
  }
}

所以我关心的两个函数是User.findOne({where: {id}})并且user.update(data)我正在使用带有 Postgres DB 的 Sequelize

基本上这两个是针对我的数据库的,所以findOne需要一个 id 来从数据库中获取用户,如果成功,它将返回一个对象

user = {
id: 1
firstName: 'John'
lastName: 'Doe'
}

所以我data在函数的参数中应该是:

data = {
id: 1
firstName: 'Jane'
lastName: 'Smith'
}

例如,我想将 John Doe 更新为 Jane Smith,并使用更新功能将其发送到数据库user.update(data)

那么我如何测试这个mocha/chai and sinon以及我正在使用proxyquire and sequelize-test-helpers我正在尝试使用chai and sinon mainly我一般是新的测试。

describe('UserService Root', function () {
   // this is the setup please remember mockModel.User from here and dummyUser as well as data and id
 
  const UserModel = { // We will change the name of this object to just User soon
    findOne: sinon.stub()
  }

  const mockModels = makeMockModels( { UserModel } );  
  delete Object.assign(mockModels, {['User']: mockModels['UserModel'] })['UserModel']

  // UserModel is now renamed to User as that is what is inside the class function itself

  const UserService = proxyquire(servicePath, {
    "../models": mockModels
  });

  // Returns a large Object of all my Models but we will be doing mockModels.User 
  const userService = new UserService(); // an instance object of the class

  const dummyUser = { User: { update: sinon.stub() } }
  
  const id = 1
  const data = {
    id: 1,
    first_name: 'Jane',
    last_name: 'Smith'
  }

  const resetStubs = () => {
    mockModels.User.findOne.resetHistory()
    dummyUser.User.update.resetHistory()
  }
  let result;

// now that is the setup now lets describe the test

  describe('User exists', () => {

    before(async () => {
      dummyUser.User.update.resolves(dummyUser);
      // mockModels.User.findOne.r is there something I need to do here?
      mockModels.User.findOne.resolves(dummyUser.User);
      result = await userService.updateUser(data);
    });

    after(resetStubs);

    it('call user.findOne() but with argument of ID how do I do that?', () => {
      expect(mockModels.User.findOne).to.have.been.called; // works ok if it called with nothing
      expect(mockModels.User.findOne).to.have.been.calledWith(id); // how can I call with arg?
    });

    it('call user.update with sinon.stub() sinon.match(data)', () => {
      expect(dummyUser.User.update).to.have.been.calledWith(sinon.match(data));
    });

    it('returns the user', () => {
      expect(result).to.deep.equal(dummyUser)
    })
  })
})

是的,我如何用 sinon 来称呼它User.findOne(with argument of id)?基本上这是它阻止。

    it('call user.findOne() but with argument of ID how do I do that?', () => {
      expect(mockModels.User.findOne).to.have.been.called; // works ok if it called with nothing
      expect(mockModels.User.findOne).to.have.been.calledWith(id); // how can I call with arg?
    });

可能在之前的块中,我是否需要为它块的 calledWith(id) 进行设置才能工作?

    before(async () => {
      dummyUser.User.update.resolves(dummyUser);
      // mockModels.User.findOne.r
      mockModels.User.findOne.resolves(dummyUser.User);
      result = await userService.updateUser(data);
    });

标签: javascriptunit-testingchaisinonsinon-chai

解决方案


推荐阅读