如何用Sinn模拟pg Pool

时间:2019-02-26 13:57:20

标签: javascript node.js sinon pg

在先前的项目中,我用mysql library模拟了Sinon。我这样做是这样的:

X.js

const con = mysql.createPool(config.mysql);
...

Some other place in the project

const rows = await con.query(query, inserts);
...

X.test.js

const sinon = require('sinon');
const mockMysql = sinon.mock(require('mysql'));
...

mockMysql.expects('createPool').returns({
        query: () => {
            // Handles the query...
        },
...

效果很好。

在另一个项目中,我尝试与Sinon一起模拟pg

pool.js

const { Pool } = require('pg');
const config = require('@blabla/config');
const pool = new Pool(config.get('database'));

module.exports = pool;

Some other place in the project

const con = await pool.connect();
const result = await con.query(...

Y.test.js

???

我不明白如何模拟connect().query()。以下方法均无效:

1:

const { Pool } = require('pg');
const config = require('@blabla/config');

const mockPool = sinon.mock(new Pool(config.get('database')));
...
mockPool.expects('connect').returns({
  query: () => {
    console.log('query here');
  },
});

1不会导致任何错误,但是使用了真正的数据库连接。

2:

const { Pool } = sinon.mock(require('pg'));
const config = require('@blabla/config');

const pool = new Pool(config.get('database'));

pool.expects('connect').returns({
  query: () => {
    console.log('query here');
  },
}); 

2 => TypeError: Pool is not a constructor

3:

const { Pool } = sinon.mock(require('pg'));
const config = require('@blabla/config');

const pool = sinon.createStubInstance(Pool);
pool.connect.returns({
  query: () => {
    console.log('query here');
  },
});

3 => TypeError: The constructor should be a function.

有人可以指出如何模拟PostgreSQL连接的正确方向吗?

2 个答案:

答案 0 :(得分:1)

示例:我有这样的postgres.js。

const { Pool } = require('pg');

const handler = {
  count: async (pgQuery) => {
    try {
      const pool = new Pool();
      const res = await pool.query(pgQuery);
      return { count: parseInt(res.rows[0].counter, 10) };
    } catch (error) {
      // Log/Throw error here.
    }
    return false;
  }
}

module.exports = handler;

我在postgres.spec.js上创建的规范测试就是这样。

const { expect } = require('chai');
const sinon = require('sinon');
const pgPool = require('pg-pool');
const handler = require('postgres.js');

describe('Postgres', function () {
  it('should have method count that bla bla', async function () {
    // Create stub pgPool query.
    const postgreeStubQuery = sinon.stub(pgPool.prototype, 'query');
    postgreeStubQuery.onFirstCall().throws('XXX');
    postgreeStubQuery.onSecondCall().resolves({
      rows: [{ counter: 11 }],
    });

    // Catch case.
    const catcher = await handler.count('SELECT COUNT()..');
    expect(catcher).to.equal(false);
    expect(postgreeStubQuery.calledOnce).to.equal(true);

    // Correct case.
    const correct = await handler.count('SELECT COUNT()..');
    expect(correct).to.deep.equal({ count: 11 });
    expect(postgreeStubQuery.calledTwice).to.equal(true);

    // Restore stub.
    postgreeStubQuery.restore();
  });
});

要存根 pool.query(),您需要存根 pg-pool 原型和方法查询。

希望这会有所帮助。

答案 1 :(得分:0)

由于您需要模拟查询的返回结果,因此我认为最简单的解决方案是从需要查询结果的代码中提取数据库。例如,您的查询结果正在返回有关某个人的信息。创建具有用于与数据库交互的特定方法的person.js模块。

您需要从数据库中获取个人信息的其他代码将不知道或不在乎您使用什么类型的数据库或如何连接到数据库,他们所关心的只是知道当需要时,person.js公开了哪些方法。

//person.js
const { Pool } = require('pg)
// do other database connection things here
const getPersonById = function (id) {
  // use your query here and return the results
}
module.exports = { getPersonById }

现在在您的测试中,您将模拟人员模块,而不是pg模块。想象一下,如果您有20个奇怪的测试都设置了模拟mysql池,那么您将其更改为pg,则必须更改所有 all 噩梦。但是通过抽象化数据库连接类型/设置,它使测试变得更加容易,因为现在您只需要存根/模拟person.js模块即可。

const person = require('../person.js') //or whatever relative file path it's in
const sinon = require('sinon')

describe('person.js', function () {
 it('is stubbed right now', function () {
  const personStub = sinon.stub(person)
  personStub.getPersonById.returns('yup')

  expect(personStub.getPersonById()).to.eq('yup')
 })
})