如何用玩笑测试unhandledRejection / uncaughtException处理程序

时间:2018-09-25 07:48:56

标签: javascript unit-testing jestjs

我有unhandledRejectionuncaughtException s的处理程序:

bin.js

['unhandledRejection', 'uncaughtException'].forEach(event => {
  process.on(event, err => logger.error(err));
});

现在我想用jest测试它们:

bin.test.js

const bin = require('../bin');

test('catches unhandled rejections', async () => {
  const error = new Error('mock error');
  await Promise.reject(error);
  expect(logger.error).toHaveBeenCalledWith(error);
});

test('catches uncaught exceptions', () => {
  const error = new Error('mock error');
  throw error;
  expect(logger.error).toHaveBeenCalledWith(error);
});

但是jest只是告诉我测试中存在错误:

  

●捕获未处理的拒绝

mock error

   8 | // https://github.com/facebook/jest/issues/5620
   9 | test('catches unhandled rejections', async () => {
> 10 |   const error = new Error('mock error');
     |                 ^
  11 |   await Promise.reject(error);
  12 |   expect(logger.error).toHaveBeenCalledWith(error);
  13 | });

  at Object.<anonymous>.test (test/bin.test.js:10:17)
     

●捕获未捕获的异常

mock error

  14 |
  15 | test('catches uncaught exceptions', () => {
> 16 |   const error = new Error('mock error');
     |                 ^
  17 |   throw error;
  18 |   expect(logger.error).toHaveBeenCalledWith(error);
  19 | });

  at Object.<anonymous>.test (test/bin.test.js:16:17)

有没有办法对此进行测试?

这可能与以下内容有关:https://github.com/facebook/jest/issues/5620

2 个答案:

答案 0 :(得分:1)

我的测试策略是使用 jest.spyOn(object, methodName) 将 spy 安装到 process.on()logger.error 方法上。这样做之后,这些方法都没有副作用。然后,您可以在隔离的环境中测试您的代码逻辑。

此外,还有几点需要注意:

  • 您应该监视 require('./bin') 语句之前的函数。因为当你加载 bin.js 模块时,代码会被执行。
  • 您应该在 beforeEach 挂钩中使用 jest.resetModules() 来重置模块注册表 - 所有必需模块的缓存。为什么?因为 require() 缓存其结果。因此,第一次需要一个模块时,它的初始化代码就会运行。之后,缓存只返回 module.exports 的值,无需再次运行初始化代码。但是我们有两个测试用例,我们希望模块范围内的代码被执行两次。

现在,这是示例:

bin.js

const logger = require('./logger');

['unhandledRejection', 'uncaughtException'].forEach((event) => {
  process.on(event, (err) => logger.error(err));
});

logger.js

const logger = console;

module.exports = logger;

bin.test.js

const logger = require('./logger');

describe('52493145', () => {
  beforeEach(() => {
    jest.resetModules();
  });
  afterEach(() => {
    jest.restoreAllMocks();
  });
  test('catches unhandled rejections', () => {
    const error = new Error('mock error');
    jest.spyOn(process, 'on').mockImplementation((event, handler) => {
      if (event === 'unhandledRejection') {
        handler(error);
      }
    });
    jest.spyOn(logger, 'error').mockReturnValueOnce();
    require('./bin');
    expect(process.on).toBeCalledWith('unhandledRejection', expect.any(Function));
    expect(logger.error).toHaveBeenCalledWith(error);
  });

  test('catches uncaught exceptions', () => {
    const error = new Error('mock error');
    jest.spyOn(process, 'on').mockImplementation((event, handler) => {
      if (event === 'uncaughtException') {
        handler(error);
      }
    });
    jest.spyOn(logger, 'error').mockReturnValueOnce();
    require('./bin');
    expect(process.on).toBeCalledWith('uncaughtException', expect.any(Function));
    expect(logger.error).toHaveBeenCalledWith(error);
  });
});

单元测试结果:

 PASS  examples/52493145/bin.test.js
  52493145
    ✓ catches unhandled rejections (5 ms)
    ✓ catches uncaught exceptions (1 ms)

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |     100 |      100 |     100 |     100 |                   
 bin.js    |     100 |      100 |     100 |     100 |                   
 logger.js |     100 |      100 |     100 |     100 |                   
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        2.73 s, estimated 4 s

源代码:https://github.com/mrdulin/jest-v26-codelab/tree/main/examples/52493145

答案 1 :(得分:-2)

将其放入try catch中将有所帮助:

const error = new Error('mock error');

尝试{

await Promise.reject(error);

} 抓住(错误){

   expect(logger.error).toHaveBeenCalledWith(error);

}