【问题标题】:How to mock test a Node.js CLI with Jest?如何使用 Jest 模拟测试 Node.js CLI?
【发布时间】:2018-05-19 07:01:51
【问题描述】:

我一开始就卡住了,只需要 CLI 并捕获它的输出。我尝试了两种方法,但都不起作用。

这是我的 cli.js:

#!/usr/bin/env node

console.log('Testing...');
process.exit(0);

这是我的 cli.test.js:

test('Attempt 1', () => {
    let stdout = require("test-console").stdout;
    let output = stdout.inspectSync(function() {
        require('./cli.js');
    });
    expect(output).toBe('Testing...');
});

test('Attempt 2', () => {
    console.log = jest.fn();
    require('./cli.js');
    expect(console.log.calls).toBe(['Testing...']);
});

实际上正在运行哪个测试并不重要,输出总是:

$ jest

 RUNS  bin/cli.test.js
Done in 3.10s.

【问题讨论】:

  • 我想这是因为 process.exit。尝试存根。
  • 你说的很对,谢谢!这也是我使用指挥官的实际项目中的问题。这一行在这里:github.com/tj/commander.js/blob/…
  • 当然……我想我可以简单地使用 outputHelp() 而不是 help()。
  • 很高兴它有帮助。我添加了答案,以防其他人遇到同样的问题。

标签: node.js jestjs


【解决方案1】:

Node.js CLI 应用程序除了对环境的依赖外,与其他应用程序没有什么不同。他们预计会广泛使用process 成员,例如:

  • process.stdin
  • process.stdout
  • process.argv
  • process.exit

如果使用了这些东西中的任何一个,则应该对它们进行相应的模拟和测试。

由于直接调用console.log进行输出,所以直接窥探它没有问题,尽管也可以使用像test-console这样的帮助包。

在这种情况下,process.exit(0) 在导入的文件中被调用,因此 spec 文件提前退出,下一个 Done 输出来自父进程。它应该被存根。抛出错误是必要的,以便停止代码执行 - 以模仿正常行为:

test('Attempt 2', () => {
    const spy = jest.spyOn(console, 'log');
    jest.spyOn(process, 'exit').mockImplementationOnce(() => {
      throw new Error('process.exit() was called.')
    });

    expect(() => {
      require('./cli.js');
    }).toThrow('process.exit() was called.');
    expect(spy.mock.calls).toEqual([['Testing...']]);
    expect(process.exit).toHaveBeenCalledWith(0);
});

【讨论】:

  • 您介意添加一个拦截 process.stdout 的示例吗?因为 test-console 的返回是不可用的(可能是因为 jest 挂钩到 stdout 并将颜色和元数据添加到输出?)并且 process.stdout.on('data', ...) 在使用时会导致“读取 ENOTCONN”错误在测试中。
  • 我没有用 Jest 做那个,所以我不知道有什么陷阱。我想这是已知问题,github.com/facebook/jest/issues/1120,并且监视控制台方法是正确的做法。看起来 Jest 与 std* 流混淆了。我想一种解决方法是使用 child_process 运行测试脚本并从其标准输出中读取(可能会很麻烦,因为您需要包装脚本来为原始脚本提供模拟)。如果这是您的情况,看起来很复杂,值得单独提出一个问题。
  • 啊,我明白了 - 不知道 Jest 在详细模式下的输出是什么样的。控制台的问题是某些包可能会直接写入标准输出:github.com/tj/commander.js/blob/… 让我想知道这是否是好的代码设计并且应该被报告。无论如何-感谢该链接!
  • 有道理。我猜你可能想模拟 Command.prototype.outputHelp。
  • 使用 try...catch 抑制错误并不是规范中的好习惯。可能还有其他错误会导致没有反馈。由于存在特定错误,因此应使用 toThrow 进行断言。
猜你喜欢
  • 2020-05-28
  • 1970-01-01
  • 2020-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-26
  • 2020-08-26
相关资源
最近更新 更多