Как издеваться над require.main в узле?

#javascript #node.js #unit-testing #module #mocking

#javascript #node.js #модульное тестирование #модуль #издевательство

Вопрос:

У меня есть модуль, который не должен вызываться непосредственно из командной строки с помощью Node. Для этой цели я проверяю основной модуль, как указано в документации:

 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. Почему вам обязательно нужно, чтобы эта строка была закрыта? Эта ветвь предназначена специально для запуска приложения — для тестирования я бы просто запустил приложение и убедился, что оно работает должным образом. 100% покрытие кода — опасная метрика.

Ответ №1:

Прошло 3 года, но я смог смоделировать это условие.

Концепция: заглушка / макет функции сравнения, которая сравнивает между require.main и module .

Для этого примера ниже: я использую модули: rewire, 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');
  });
});
  

Затем, когда я запускаю test и coverage, вот результат.

 $ 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 легко протестировать. 🙂