【问题标题】:Function stub with Sinon when modules are required inside functions函数内部需要模块时使用 Sinon 的函数存根
【发布时间】:2021-01-24 10:12:31
【问题描述】:

我正在尝试将函数存根以进行单元测试,但我不确定这是否可行,或者我应该在能够做到之前进行更改。我会尽量说明情况

文件aController.js

...
module.exports = (sqlConnection) => {

...

return {
    ...
    aControllerFunction,
    ...
}

function aControllerFunction(req, res, next) {
  const aService = require('../services/aService')(sqlConnection, req.models)
  ...

  aService.aServiceFunction(req.a, req.b)
}
...
}
...

文件aService.js

...
module.exports = (sqlConnection, models) => {

return {
    ...
    aServiceFunction,
    ...
}

...

function aServiceFunction(a, b) {

  
  ...

  models.aModel.update(a)
  sqlConnection.queryAsync(`UPDATE... ${a}`)
  ...
}
...
}
...

我想对函数 aControllerFunctionaServiceFunction 进行单元测试。

对于aControllerFunction,我应该存根aService.aServiceFunction,对于aServiceFunction.aServiceFunction,我应该存根sqlConnection.queryAsyncmodels.aModel.update

这种结构可以实现吗,还是我应该先改变它?我尝试这样做,但我发现很难存根,因为需求在函数内部。

【问题讨论】:

  • 你是否返回aControllerFunction 函数,同样的aServiceFunction 函数?否则,它们是私有的。无法在测试文件中获取它们。
  • @slideshowp2 感谢您的回答,我更新了问题。控制器和服务中有导出,因为正在导出功能。但是要求在功能范围内。有没有办法可以消除它的行为?谢谢

标签: javascript node.js unit-testing sinon stub


【解决方案1】:

为了测试aControllerFunction,我们需要额外的包proxyquire。我们可以使用这个包来模拟从模块导出的函数(serviceFactory)。这称为link seams

例如

controllers/aController.js:

module.exports = (sqlConnection) => {
  return {
    aControllerFunction,
  };

  function aControllerFunction(req, res, next) {
    const aService = require('../services/aService')(sqlConnection, req.models);
    aService.aServiceFunction(req.a, req.b);
  }
};

controllers/aController.test.js:

const proxyquire = require('proxyquire');
const sinon = require('sinon');

describe('aController', () => {
  it('should pass', () => {
    const sqlConnection = {};
    const req = { models: {}, a: 'a', b: 'b' };
    const aService = { aServiceFunction: sinon.stub() };
    const serviceFactory = sinon.stub().returns(aService);
    const ControllerFactory = proxyquire('./aController', {
      '../services/aService': serviceFactory,
    });
    const { aControllerFunction } = ControllerFactory(sqlConnection);
    aControllerFunction(req);
    sinon.assert.calledWithExactly(serviceFactory, {}, {});
    sinon.assert.calledWithExactly(aService.aServiceFunction, 'a', 'b');
  });
});

services/aService.js:

module.exports = (sqlConnection, models) => {
  return {
    aServiceFunction,
  };

  function aServiceFunction(a, b) {
    models.aModel.update(a);
    sqlConnection.queryAsync(`UPDATE... ${a}`);
  }
};

services/aService.test.js:

const serviceFactory = require('./aService');
const sinon = require('sinon');

describe('aService', () => {
  it('should pass', () => {
    const sqlConnection = {
      queryAsync: sinon.stub(),
    };
    const models = {
      aModel: {
        update: sinon.stub(),
      },
    };
    const { aServiceFunction } = serviceFactory(sqlConnection, models);
    aServiceFunction('a', 'b');
    sinon.assert.calledWithExactly(models.aModel.update, 'a');
    sinon.assert.calledWithExactly(sqlConnection.queryAsync, 'UPDATE... a');
  });
});

带有覆盖率报告的单元测试结果:

  aController
    ✓ should pass

  aService
    ✓ should pass


  2 passing (35ms)

-----------------|---------|----------|---------|---------|-------------------
File             | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------------|---------|----------|---------|---------|-------------------
All files        |     100 |      100 |     100 |     100 |                   
 controllers     |     100 |      100 |     100 |     100 |                   
  aController.js |     100 |      100 |     100 |     100 |                   
 services        |     100 |      100 |     100 |     100 |                   
  aService.js    |     100 |      100 |     100 |     100 |                   
-----------------|---------|----------|---------|---------|-------------------

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 2021-11-27
    • 2016-06-19
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 2020-03-29
    相关资源
    最近更新 更多