Sinon stub out 模块的功能

Sinon stub out module's function

假设我这里有一个文件:

// a.js
const dbConnection = require('./db-connection.js')

module.exports = function (...args) {
   return async function (req, res, next) {
      // somethin' somethin' ...
      const dbClient = dbConnection.db
      const docs = await dbClient.collection('test').find()
 
      if (!docs) {
         return next(Boom.forbidden())
      }
   }
}

db-connection.js 看起来像这样:

const MongoClient = require('mongodb').MongoClient
const dbName = 'test'
const url = process.env.MONGO_URL

const client = new MongoClient(url, { useNewUrlParser: true,
  useUnifiedTopology: true,
  bufferMaxEntries: 0 // dont buffer querys when not connected
})

const init = () => {
  return client.connect().then(() => {
    logger.info(`mongdb db:${dbName} connected`)

    const db = client.db(dbName)
  })
}

/**
 * @type {Connection}
 */
module.exports = {
  init,
  client,
  get db () {
    return client.db(dbName)
  }
}

并且我有一个测试将 find() 方法存根到 return 至少为真(为了测试 a.js 的 return 值是否为是的。我该怎么做?

单元测试策略是存根数据库连接,我们不需要连接真正的mongo数据库服务器。这样我们就可以运行在与外界环境隔离的环境中测试用例。

您可以使用 stub.get(getterFn)dbConnection.db getter 替换新的 getter。

因为 MongoDB 客户端初始化发生在您需要 db-connection 模块时。在需要 adb-connection 模块之前,您应该从环境变量中为 MongoClient 提供正确的 URL。否则,MongoDB nodejs 驱动程序将抛出一个无效的 url 错误。

例如

a.js:

const dbConnection = require('./db-connection.js');

module.exports = function () {
  const dbClient = dbConnection.db;
  const docs = dbClient.collection('test').find();

  if (!docs) {
    return true;
  }
};

db-connection.js:

const MongoClient = require('mongodb').MongoClient;
const dbName = 'test';
const url = process.env.MONGO_URL;

const client = new MongoClient(url, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

const init = () => {
  return client.connect().then(() => {
    console.info(`mongdb db:${dbName} connected`);
    const db = client.db(dbName);
  });
};

module.exports = {
  init,
  client,
  get db() {
    return client.db(dbName);
  },
};

a.test.js:

const sinon = require('sinon');

describe('a', () => {
  afterEach(() => {
    sinon.restore();
  });
  it('should find some docs', () => {
    process.env.MONGO_URL = 'mongodb://localhost:27017';
    const a = require('./a');
    const dbConnection = require('./db-connection.js');

    const dbStub = {
      collection: sinon.stub().returnsThis(),
      find: sinon.stub(),
    };
    sinon.stub(dbConnection, 'db').get(() => dbStub);
    const actual = a();
    sinon.assert.match(actual, true);
    sinon.assert.calledWithExactly(dbStub.collection, 'test');
    sinon.assert.calledOnce(dbStub.find);
  });
});

测试结果:

  a
    ✓ should find some docs (776ms)


  1 passing (779ms)

------------------|---------|----------|---------|---------|-------------------
File              | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------------|---------|----------|---------|---------|-------------------
All files         |      75 |       50 |      25 |      75 |                   
 a.js             |     100 |       50 |     100 |     100 | 7                 
 db-connection.js |      60 |      100 |       0 |      60 | 11-13,21          
------------------|---------|----------|---------|---------|-------------------