Jest中异步函数异常测试的正确姿势:expect().rejects用法详解

Jest中异步函数异常测试的正确姿势:expect().rejects用法详解

在Jest中测试异步函数抛出异常时,理解expect().rejects的正确用法至关重要。本文将详细阐述如何正确使用rejects断言一个Promise被拒绝并抛出特定错误,并指出常见的错误模式:将异步函数包裹在另一个函数中传递给expect,强调rejects旨在直接作用于Promise对象,而非函数。

理解Jest中的异步错误测试

javascript的异步编程中,promise是处理异步操作结果的核心机制。当异步操作失败时,promise会进入拒绝(rejected)状态,并通常伴随一个错误对象。jest提供了.rejects匹配器,专门用于测试promise是否被拒绝,并结合.tothrowerror()来验证拒绝的原因是否是预期的错误。

与同步函数的错误测试不同,同步函数使用expect(() => syncFun()).toThrowError(),需要将可能抛出错误的函数包裹在一个匿名函数中。然而,对于异步函数,.rejects的工作方式有所不同。

expect().rejects 的核心原理

expect().rejects旨在直接作用于一个Promise对象。当expect接收到一个Promise时,它会等待该Promise解析(resolve)或拒绝(reject)。如果Promise被拒绝,rejects链上的匹配器(如.toThrowError())将对拒绝值进行验证。

正确的异步错误测试方式

测试一个预期会抛出错误的异步函数asyncFun()的正确方式是直接将asyncFun()的调用结果(即一个Promise)传递给expect。

示例代码:

// 假设有一个异步函数,它会返回一个被拒绝的Promise async function asyncFunThatThrows() {   return new Promise((resolve, reject) => {     // 模拟异步操作后抛出错误     setTimeout(() => {       reject(new Error('Async operation failed!'));     }, 100);   }); }  // 或者一个async函数直接抛出错误 async function anotherAsyncFunThatThrows() {   await new Promise(r => setTimeout(r, 50)); // 模拟一些异步工作   throw new Error('Another async error!'); }  describe('Testing async functions that throw errors', () => {   test('should correctly catch an error from a rejected promise', async () => {     const errorObj = new Error('Async operation failed!');     // 直接将Promise传递给expect     await expect(asyncFunThatThrows()).rejects.toThrowError(errorObj);   });    test('should correctly catch an error from an async function that throws', async () => {     const errorObj = new Error('Another async error!');     // 直接将Promise(async函数的返回值)传递给expect     await expect(anotherAsyncFunThatThrows()).rejects.toThrowError(errorObj);   }); });

在这种模式下,asyncFunThatThrows()或anotherAsyncFunThatThrows()被调用后会立即返回一个Promise。await expect(…)会等待这个Promise完成,如果它被拒绝,rejects.toThrowError()就会对拒绝值进行匹配。

常见的误区与原因分析

一个常见的错误是将异步函数再次包裹在一个匿名异步函数中,然后将其传递给expect。

Jest中异步函数异常测试的正确姿势:expect().rejects用法详解

可灵AI

可灵AI:新一代AI创意生产力平台

Jest中异步函数异常测试的正确姿势:expect().rejects用法详解11061

查看详情 Jest中异步函数异常测试的正确姿势:expect().rejects用法详解

错误示例:

// 假设 asyncFun() 是一个会返回被拒绝Promise的异步函数 await expect(async () => {   await asyncFun(); }).rejects.toThrowError(errorObj);

为什么这是错误的或不被推荐的:

  1. expect接收的是函数而非Promise: 在这个例子中,expect接收到的是一个匿名异步函数 async () => { await asyncFun() },而不是asyncFun()返回的Promise。尽管Jest在内部可能对传入的函数进行了某种处理,但这不是rejects设计的初衷和推荐用法。
  2. rejects期望Promise: .rejects匹配器是为Promise设计的。当它接收到一个函数时,其行为可能不符合预期,或者在未来的Jest版本中可能不再支持。Jest的官方文档明确指出.rejects应该用于Promise。
  3. 不必要的复杂性: 将一个异步函数包裹在另一个异步函数中,增加了不必要的嵌套和复杂性,同时也模糊了测试的意图。

这种写法在某些情况下可能“看似有效”,但它不是Jest官方文档推荐或保证的行为。正确的做法是始终将异步函数执行后返回的Promise直接传递给expect。

注意事项

  • await的重要性: 在使用expect().rejects时,必须在expect调用前使用await。这是因为expect().rejects本身返回一个Promise,你需要等待这个Promise解析,以确保断言逻辑能够执行。
  • Promise的拒绝状态: 只有当Promise进入拒绝状态时,.rejects才能捕获到错误。如果异步函数在执行过程中抛出异常,但没有被try…catch捕获并导致Promise拒绝,那么测试可能无法按预期工作。确保你的异步函数在失败时返回一个被拒绝的Promise。

总结

在Jest中测试异步函数抛出异常时,请牢记expect().rejects是为Promise设计的。正确的做法是直接将异步函数调用后返回的Promise传递给expect,例如 await expect(asyncFunctionCall()).rejects.toThrowError(error)。避免将异步函数包裹在另一个匿名函数中传递给expect,以确保测试的准确性、可读性以及与Jest最佳实践的一致性。遵循这一原则,你的异步错误测试将更加健壮和可靠。

javascript java ai 为什么 JavaScript try catch Error 对象 promise 异步

上一篇
下一篇