首页 > 解决方案 > 如何使用 Jest 在 Nodejs 中对 uncaughtException 和 unhandledRejection 进行单元测试

问题描述

我已经建立了一个这样的错误处理程序:

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

module.exports = () => {
  process.on('uncaughtException', (err) => {
    logger.error(err.message, err);
    process.exit(1);
  });

  process.on('unhandledRejection', (err) => {
    throw err;
  });
};

现在我想对此进行单元测试,主要是第一个事件监听器。我当前的测试如下所示:

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

describe('Uncaught Exceptions', () => {
  it('should log the exception and exit the process', () => {
    process.exit = jest.fn();
    logger.error = jest.fn();
    jest.fn(() => {
      throw new Error('fake error');
    })();

    expect(logger.error).toBeCalledTimes(1);
    expect(process.exit).toBeCalledTimes(1);
    expect(process.exit).toBeCalledWith(1);
  });
});

上面的代码在抛出新的错误行时失败,尽管有 --verbose 标志,但 jest 没有将有用的信息记录到控制台。
有关如何对此类模块进行单元测试的任何建议?我浏览了下面的链接,但一无所获。
如何用 jest 测试 unhandledRejection / uncaughtException 处理程序

标签: node.jsunit-testingjestjs

解决方案


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

例如

unhandledErrors.js

module.exports = () => {
  process.on('uncaughtException', (err) => {
    console.error(err.message);
    process.exit(1);
  });

  process.on('unhandledRejection', (err) => {
    throw err;
  });
};

unhandledErrors.test.js

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

describe('65386298', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  it('should handle uncaughtException', () => {
    const mError = new Error('Server internal error');
    jest.spyOn(process, 'on').mockImplementation((event, handler) => {
      if (event === 'uncaughtException') {
        handler(mError);
      }
    });
    jest.spyOn(console, 'error').mockReturnValueOnce();
    jest.spyOn(process, 'exit').mockReturnValueOnce();
    unhandledErrors();
    expect(process.on).toBeCalledWith('uncaughtException', expect.any(Function));
    expect(process.exit).toBeCalledWith(1);
    expect(console.error).toBeCalledWith('Server internal error');
  });

  it('should handle unhandledRejection', () => {
    const mError = new Error('dead lock');
    jest.spyOn(process, 'on').mockImplementation((event, handler) => {
      if (event === 'unhandledRejection') {
        handler(mError);
      }
    });
    expect(() => unhandledErrors()).toThrowError('dead lock');
    expect(process.on).toBeCalledWith('unhandledRejection', expect.any(Function));
  });
});

单元测试结果:

 PASS  examples/65386298/unhandledErrors.test.js
  65386298
    ✓ should handle uncaughtException (3 ms)
    ✓ should handle unhandledRejection (1 ms)

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

推荐阅读