使用 sinon 和 mocha 存根 pg-promise

Stubbing pg-promise using sinon and mocha

假设我有以下模块,如database.js

const initOptions = {}
const pgp = require('pg-promise')(initOptions)
const config = require('../../config')

const db = pgp({
  host: config.database.host,
  port: config.database.port,
  database: config.database.database,
  user: config.database.user,
  password: config.database.password
})

module.exports = db

而下面的模块为create.js

const db = require('./database')

function create (name) {
  return new Promise((resolve, reject) => {
      db.func('create', name)
      .then(data => {
        return resolve(data)
      })
      .catch(err => {
        return reject(err)
      })
  })
}

module.exports = create

我正在尝试 运行 对 create.js 进行单元测试,该单元测试将测试 db.func 是使用 'create' 作为第一个参数调用的,并且 'name'作为第二个,但实际上不需要建立数据库连接(因此测试可以 运行 离线)。

据我所知,这就是像 sinon.JS 这样的库的用途,所以我尝试创建一个测试并存根 db 对象。

const chai = require('chai')
const chaiAsPromised = require('chai-as-promised')

chai.use(chaiAsPromised)

const sinon = require('sinon')

const expect = chai.expect

const create = require('./create.js')

describe('Test Module', () => {
  it('should test stuff', () => {
    const db = require('./database')
    const dbStub = sinon.stub(db, 'func').callsFake(Promise.resolve(null))
    expect(create('test').then).to.be.a('Function')
  })
})

然而,它失败了

TypeError: Cannot redefine property: func

很可能是因为我对 sinon 的接触有限...

我如何去存根(或者我可能需要模拟?)db 函数以便我可以测试它并确保 db.func 被调用?

您可以通过在 Initialization Options 中使用 no noLocking 选项禁用锁定来使属性可配置。这允许 sinon 替换属性:

const initOptions = { noLocking : true };

相关说明:

您的 create 函数正在创建一个不必要的承诺包装器,这是一个承诺反模式。您应该 return 来自 db.func 的结果,这已经是一个承诺:

function create(name) {
      return db.func('create', name);
}

另外 callsFake 接受了一个函数,你给了它一个承诺。使用 returns 代替:

const dbStub = sinon.stub(db, 'func').returns(Promise.resolve(null))

I'm having trouble setting the noLocking option. The docs state it can be set after initialization, however if I set it with db.$config.options.noLocking = true, the same error occurs. However, if I set it in the database.js init options it works fine.

来自pg-promise的作者...

因为此时noLocking只能影响任务和事务。由于协议的 db 级别仅启动一次,因此在库初始化后设置 noLocking 不会影响它。

我刚刚更新了 documentation 来澄清它: This option is dynamic (can be set before or after initialization). However, changing it after the library's initialization will not affect Database objects that have already been created.