如何在Node中模拟require.main?

时间:2016-10-21 14:52:03

标签: javascript node.js unit-testing module mocking

我有一个模块,不应该直接从Node命令行调用。为此,我将主模块检查为indicated in the documentation

if (require.main === module) {
    console.error('This module cannot be run from the command line.');
} else {
    // Here the module logic...
}

现在我正在为这个模块编写单元测试(如果重要的话,使用Mocha / Chai),我想模拟直接从命令行调用模块的情况,当错误应该打印到stderr时。

其余的逻辑已经在测试中,但我无法通过单元测试获得require.main === module分支。我用最简洁的方法来解决这个问题就是在模块内部模拟require.main,但我不知道如何做到这一点。我们已经使用proxyquire来模拟依赖项,但在这种情况下它没有帮助。

有关如何处理此问题的任何建议吗?

1 个答案:

答案 0 :(得分:1)

已经3年了,但是我可以模拟这种情况。

概念:存根/模拟在require.mainmodule之间进行比较的比较功能。

在下面的示例中:我使用以下模块:重接线,sinon,chai,mocha和nyc。

有这个index.js

// File: index.js (original)
if (require.main === module)) {
  console.log('Run directly');
} else {
  console.log('Run NOT directly');
}

我创建了一个包含用于比较2个输入的函数的帮助器。

// File: helper.js
function runDirectly(a, b) {
  // Suppose:
  // a: require.main
  // b: module
  return (a === b);
}

module.exports = { runDirectly };

然后我将索引修改为类似的内容。

// File: index.js (modified)
const helper = require('./helper.js');

if (helper.runDirectly(require.main, module)) {
  console.log('Run directly');
} else {
  console.log('Run NOT directly');
}

当我直接从命令行尝试时,它仍然可以正常运行。

$ node index.js
Run directly
$

我创建了这个规范文件。

// File: index.spec.js
const rewire = require('rewire');
const sinon = require('sinon');
const { expect } = require('chai');
const helper = require('./helper.js');

describe('Index', function () {
  let sandbox;
  before(function () {
    sandbox = sinon.createSandbox();
  });

  afterEach(function () {
    sandbox.restore();
  });

  it('simulate run directly', function () {
    const stubHelperRunDirectly = sandbox.stub(helper, 'runDirectly');
    // Simulate require.main === module.
    stubHelperRunDirectly.returns(true);
    const stubConsoleLog = sandbox.stub(console, 'log');

    rewire('./index.js');

    expect(stubHelperRunDirectly.calledOnce).to.equal(true);
    expect(stubConsoleLog.calledOnce).to.equal(true);
    expect(stubConsoleLog.args[0][0]).to.equal('Run directly');
  });

  it('simulate run NOT directly', function () {
    const stubHelperRunDirectly = sandbox.stub(helper, 'runDirectly');
    // Simulate: require.main !== module.
    stubHelperRunDirectly.returns(false);
    const stubConsoleLog = sandbox.stub(console, 'log');

    rewire('./index.js');

    expect(stubHelperRunDirectly.calledOnce).to.equal(true);
    expect(stubConsoleLog.calledOnce).to.equal(true);
    expect(stubConsoleLog.args[0][0]).to.equal('Run NOT directly');
  });
});

然后,当我进行测试和覆盖时,这里是结果。

$ npx nyc mocha index.spec.js 


  Index
    ✓ simulate run directly
    ✓ simulate run NOT directly


  2 passing (45ms)

---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |   96.77 |      100 |   83.33 |   96.77 |                   
 helper.js     |      50 |      100 |       0 |      50 | 10                
 index.js      |     100 |      100 |     100 |     100 |                   
 index.spec.js |     100 |      100 |     100 |     100 |                   
---------------|---------|----------|---------|---------|-------------------
$

现在index.js具有100%的覆盖率,并且helper.js易于测试。 :)