应使用 .rejects 断言器验证 async 函数报错,因 async 函数同步返回 promise 而不抛错;.rejects 自动等待并提取 rejection 错误,支持 tothrow、tobeinstanceof、tomatchobject 等链式校验,语义清晰且避免 unhandledrejection 警告。

在测试中捕获 async 函数报错,核心是让测试框架明确等待 Promise 的拒绝(rejection),而不是误断言函数本身或未 await 的 Promise 实例。直接用 toThrow() 会失败,因为 async 函数总是同步返回 Promise —— 它从不“同步抛错”。
用 .rejects 断言被拒绝的 Promise
Jest 等主流测试框架提供 .rejects 断言器,专为验证 Promise 拒绝设计。它自动等待 Promise settle,并在 rejection 时提取 error 做后续匹配:
-
简洁可靠:无需手动 try/catch,也不会触发
unhandledrejection警告 -
支持链式校验:可接
toThrow('msg')、toBeInstanceOf(CustomError)、toMatchObject({ code: 'VALIDATION_FAILED' })等 -
语义清晰:
expect(asyncFn()).rejects.toThrow(...)直观表达“调用该函数应导致错误”
避免常见误写方式
这些写法看似合理,但实际无法正确捕获异步错误:
- ❌ expect(asyncFn()).toThrow():断言的是 Promise 对象本身,而 Promise 实例不会抛出错误
- ❌ expect(() => asyncFn()).toThrow():断言的是一个返回 Promise 的函数,它本身是同步执行且无异常
- ❌ await asyncFn(); expect(...).toThrow():await 后错误已抛出,测试提前终止,断言不执行
- ❌ expect(asyncFn()).rejects.toThrow(...) 但没 return 或 await 测试函数:Jest 不等待,测试可能在 Promise settle 前就通过
需要深度检查错误细节时的处理
当需验证错误堆栈、自定义属性或多个字段时,.rejects 仍适用,只需换用更精确的匹配器:
- 验证错误类型:
expect(fn()).rejects.toBeInstanceOf(ValidationError) - 比对错误结构:
expect(fn()).rejects.toMatchObject({ message: 'required', field: 'email' }) - 检查原始 error 实例(慎用):
expect(fn()).rejects.toEqual(new ValidationError('...'))(注意 Error 对象不满足===,一般不推荐toEqual全量比较)
非 Jest 环境或需完全控制流程时
若用其他测试框架(如 Vitest 基础配置、Mocha)或需在 catch 中做额外操作(如日志、状态重置),可手动 try/catch,但必须确保:
- 在
try中 await 调用 async 函数 -
catch中有明确的expect断言 - 在
try块末尾加兜底逻辑(如expect(true).toBe(false)),防止无错误时“静默通过”











