【问题标题】:How do I test the code in a "if (require.main === module)" section of a Node.js script using Jest?如何使用 Jest 测试 Node.js 脚本的“if (require.main === module)”部分中的代码?
【发布时间】:2020-08-27 20:22:14
【问题描述】:

我写了一个这样的函数:

const myFunction = () => {
  return 'text';
};
exports.myFunction = myFunction;
if (require.main === module) {
  console.log(myFunction());
}

这是我的测试:

const { myFunction } = require('../myFunction');

describe('test', () => {
  it('should return the text', () => {
    expect(myFunction()).toMatch('text');
  });
});

根据代码覆盖工具,代码中的每一行都被覆盖了除了这一行:

console.log(myFunction());

基于 cmets,我认为现实可能是这条线无法进行测试,所以我正在更新我的问题:
我该怎么做:

  1. 用 Jest 测试这条线,了解它可能实际上勾选了“已覆盖”框,但我可以从字面上测试它。因为并非我的每个文件在该块中都有如此琐碎的代码。有时我确实想真正测试一下。
  2. 导致覆盖率统计显示文件为 100% 覆盖率?不是因为我很迂腐,而是我喜欢使用覆盖率报告来查找需要添加测试的内容,而我的报告中有几十个“假阴性”让这变得更加困难。

【问题讨论】:

  • (魔鬼的拥护者)该行没有导出。它将如何进行测试?
  • 你应该使用 child_process 调用来运行它
  • 如果你想要 100% 闪亮并且不想重新考虑你的方法,请添加 /* istanbul ignore next */ :)
  • @YuryTarabanko 这实际上可能是最好的解决方案。也许我应该改写我的问题以允许它作为可能的答案?我宁愿实际上能够在那个 if 块中测试代码,但老实说,我没想过只是排除它,在某些情况下,这可能是“闪亮 100%”的正确答案。
  • 在该模块之外无法访问。这就是我第一条评论的重点。此外,所有这些逻辑都在执行 console.log。人们会质疑为什么首先需要这种逻辑。

标签: javascript node.js jestjs


【解决方案1】:

根据 cmets 中的建议,我发现我可以在测试中使用 child_process exec 调用来测试命令行的输出,如下所示:

const util = require('util');
const exec = util.promisify(require('child_process').exec);
const { myFunction } = require('../myFunction');

describe('test', () => {
  it('should return the text', () => {
    expect(myFunction()).toBe('text');
  });
  it('should return the text when called via command line too', async () => {
    const { stdout } = await exec('node myFunction', {
      encoding: 'utf8',
    });
    expect(stdout).toBe('text\n');
  });
});

进一步的 cmets 指出,如果不导出那段代码,Jest 永远看不到它,因此永远不会对其进行测试,这意味着它永远不会显示为“已覆盖”。因此,一旦我对它“测试得足够好”感到满意,我可以通过在有问题的行之前添加/* istanbul ignore next */ 来将其排除在我的报告中,如下所示:

const myFunction = () => {
  return 'text';
};
exports.myFunction = myFunction;
if (require.main === module) {
  /* istanbul ignore next */
  console.log(myFunction());
}

【讨论】:

    【解决方案2】:

    正如here 解释的那样,Node.js require 使用Module.wrapper 中指定的包装代码包装脚本内容,并使用vm.runInThisContext 对其进行评估。这可以在测试中实现。可以是这样的:

    let Module = require('module');
    
    ...
    
    jest.resetModules();
    jest.spyOn(console, 'log');
    
    let myModPath = require.resolve('../myFunction');
    let wrapper = Module.wrap(fs.readFileSync(myModPath));
    let compiledWrapper = vm.runInThisContext(wrapper, {});
    let mockModule = new Module(myModPath);
    let mockExport = mockModule.exports;
    let mockRequire = Module.createRequire(myModPath);
    mockRequire.main = mockModule;
        
    wrapper(mockExport, mockRequire, mockModule, path.basename(myModPath), path.dirname(myModPath));
    
    expect(console.log).toBeCalledWith('test');
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-07
      • 2018-08-26
      • 2018-08-09
      • 2017-09-01
      • 1970-01-01
      • 2021-01-06
      • 2016-09-05
      • 2021-11-02
      相关资源
      最近更新 更多