【问题标题】:Stubbing pg-promise using sinon and mocha使用 sinon 和 mocha 存根 pg-promise
【发布时间】:2017-10-20 18:10:51
【问题描述】:

假设我有以下模块,如 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

很可能是因为我接触诗侬的机会有限……

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

【问题讨论】:

  • 该对象的属性func是不可配置的,这意味着sinon不能用Object.defineProperty替换属性。
  • 这也是我通过研究可以得出的结论。但是,我正在寻找是否有任何其他方法可以使用 pg-promise 来做到这一点。不能用 pg-promise 进行离线单元测试是不可能的

标签: node.js mocha.js sinon pg-promise sinon-chai


【解决方案1】:

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

const initOptions = { noLocking : true };

关于相关说明:

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

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

另外callsFake 接受一个函数,你给它一个承诺。请改用returns

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

我在设置noLocking 选项时遇到问题。文档声明它可以在初始化后设置,但是如果我使用db.$config.options.noLocking = true 设置它,则会发生同样的错误。但是,如果我在 database.js 初始化选项中设置它,它就可以正常工作。

来自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.

【讨论】:

  • 谢谢,这听起来是正确的解决方案!但是,我无法设置 noLocking 选项。文档声明它可以在初始化后设置,但是如果我使用 db.$config.options.noLocking = true 设置它,则会发生相同的错误。但是,如果我在 database.js 初始化选项中设置它,它就可以正常工作。不过,将其设置在 database.js 模块中并不是最佳选择。有什么想法吗?
  • @MadsRC,说实话,我不知道,我认为您不太可能像那样设置该选项。一旦对象设置为不可配置,任何人都无法将其重置为可配置。
  • @MadsRC,如果您的 ENV 正在开发,您可以做的只是将选项添加到您的初始化选项中。这样您仍然可以在生产时锁定它。
  • 这就是我实际所做的!尽管即使我在测试中存根 db.func 以返回 Promise.resolve(nulll) (如您所建议的那样),但当我调用 create 时,db 函数实际上仍然连接到数据库并创建(我碰巧有一个数据库正在监听localhost,因为我正在测试)。这是预期的行为,还是 sinon.stub 不应该覆盖 create.js 中引用的 db.func ?
猜你喜欢
  • 1970-01-01
  • 2015-12-01
  • 2018-06-20
  • 1970-01-01
  • 2016-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-07
相关资源
最近更新 更多