简体   繁体   English

如何使用 Jest 测试 Node.js 脚本的“if (require.main === module)”部分中的代码?

[英]How do I test the code in a “if (require.main === module)” section of a Node.js script using Jest?

I have written a function like this:我写了一个这样的函数:

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

and this is my test:这是我的测试:

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

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

According to code coverage tools, every line in the code is covered except for this line line:根据代码覆盖工具,除了这一行之外,代码中的每一行都被覆盖

console.log(myFunction());

Based on comments, I think maybe the reality is that this line cannot be tested, so I'm updating my question:根据评论,我认为现实可能是这条线无法测试,所以我正在更新我的问题:
How can I:我怎样才能:

  1. Test this line with Jest, understanding that it may not actually tick the "covered" box, but so I can literally test it.用 Jest 测试这一行,理解它实际上可能不会勾选“覆盖”框,但我可以从字面上测试它。 Because not every one of my files has such trivial code in that block.因为并非我的每个文件都在该块中包含如此琐碎的代码。 Sometimes I do want to test it for real.有时我确实想对其进行真实测试。
  2. Cause the coverage statistic to show the file as 100% covered?导致覆盖率统计显示文件为 100% 覆盖? Not because I am pedantic, but I like using the coverage report to find things I need to add tests for, and having dozens of "false negatives" in my report makes that more difficult.不是因为我学究,而是我喜欢使用覆盖率报告来查找我需要添加测试的内容,并且在我的报告中包含数十个“假阴性”使这变得更加困难。

Based on a suggestion in the comments, I found that I can use a child_process exec call within the test to test the output from the command line like this:根据评论中的建议,我发现我可以在测试中使用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');
  });
});

Further comments pointed out that without exporting that section of code, Jest can never see it, and hence, never test it, meaning it will never show as "covered".进一步的评论指出,如果不导出那部分代码,Jest 永远看不到它,因此永远不要测试它,这意味着它永远不会显示为“已覆盖”。 Therefore, once I am satisfied that it is "tested well enough" I can exclude it form my report by adding /* istanbul ignore next */ before the offending line like this:因此,一旦我对它“测试得足够好”感到满意,我可以通过在违规行之前添加/* istanbul ignore next */将其排除在我的报告中,如下所示:

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

As explained here , Node.js require wraps script contents with wrapper code specified in Module.wrapper and evaluates it with vm.runInThisContext .正如解释在这里,Node.js的require ,在规定的包装代码包装脚本内容Module.wrapper ,并对其进行评估vm.runInThisContext This can be implemented in a test.这可以在测试中实现。 It can be something like:它可以是这样的:

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');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM