返回

神秘的Promise:Asynchronous Promise单元测试的隐形魔法

前端

虽然 Promise 在单元测试中很容易设置,但测试它们的“结果”却不是一件容易的事,因为它们是异步的。换句话说,无法使用 await 将测试代码恰好阻塞到 catch 在 Event Loop 中被调用后的时机,从而检测到 catch 的执行,通过测试。

因此,每个尚未处理的错误都会无情地通过单元测试。反过来,意味着测试人员必须通过各种手动手段(例如,在 console 上打印消息或将异常重新抛出)来发现这些错误。

值得庆幸的是,有一个神奇的解决方案可以解决这个问题。它允许我们将 catch 块中的所有操作直接放到我们的测试框架内,用同步化的代码做异步的事情。

异步 Promise 单元测试的超级解决方案

  1. 在文件或测试模块的顶部导入必要的库。
const { expect } = require('chai');
const sinon = require('sinon');
  1. 将它包装在适当的“try”块中。
it('should async do something and test the result', async () => {
  try {
    await Promise.resolve('done').then(sinon.match.any);
  } catch (err) {
    // Handle error
  }
});
  1. 在 Promise 中执行测试逻辑。
it('should async do something and test the result', async () => {
  try {
    await Promise.resolve('done').then(sinon.match.any);
    expect(true).to.equal(true); // Passed test assertion
  } catch (err) {
    // Handle error
  }
});
  1. 处理异常并编写你喜欢的断言。
it('should async do something and test the result', async () => {
  try {
    await Promise.reject('error').then(sinon.match.any);
  } catch (err) {
    expect(err).to.equal('error'); // Passed test assertion
  }
});

这种方法不仅可以进行同步式断言,还可以使用 Sinon.JS 来验证异步回调。

it('should async do something and test the result', async () => {
  try {
    const callback = sinon.spy();
    await Promise.resolve('done').then(callback);
    sinon.assert.calledOnce(callback); // Passed test assertion
  } catch (err) {
    // Handle error
  }
});

测试中如何处理未捕获的异常

未捕获的异常通常是通过测试框架的全局错误处理程序捕获的。在 Mocha 中,这是一个名为 Mocha.Runner.uncaught() 的方法。

有两种方法可以获取这些错误。第一种是使用 Mocha.Runner.uncaught() 方法,它将返回一个包含所有捕获错误的数组。

const runner = new Mocha.Runner();
runner.on('error', (err) => {
  console.error(err.stack || err);
});

runner.run();

第二种方法是创建一个自定义全局错误处理程序并将其分配给 process.on('uncaughtException')。

process.on('uncaughtException', (err) => {
  console.error(err.stack || err);
});

结论

希望本文能帮助你更有效地测试 JavaScript 中的 Promise。无论是使用 try-catch 语句还是断言库,你都可以轻松地检测和处理异步操作中的错误。