在 async 测试中应使用 expect(...).rejects 匹配器明确预期 Promise 拒绝,而非仅靠 try/catch;若手动捕获,必须在 catch 中断言错误或显式抛出,避免未处理 rejection 导致假通过。

在 async 测试中正确捕获拒绝状态,关键不是“用 try/catch 包裹 await”,而是让测试框架明确知道你**预期这个 Promise 会 reject**,并主动验证错误类型或消息。否则,未处理的 rejection 会触发全局 unhandledrejection,导致测试失败或静默忽略。
使用 expect(...).rejects 匹配器(推荐)
这是 Jest 等主流测试框架提供的语义化方式,简洁、可读性强,且自动处理异步生命周期:
- 它底层会等待 Promise settle,并在 resolve 时自动让测试失败,只在 reject 时继续执行断言
- 支持链式断言,比如检查错误构造函数、message 正则匹配、属性值等
示例:
test('fetchUser 抛出 NetworkError 时应拒绝', async () => {
// 模拟失败请求
jest.mock('./api', () => ({
fetchUser: () => Promise.reject(new NetworkError('timeout'))
}));
<p>await expect(fetchUser(123)).rejects.toThrow('timeout');
// 或更精确:
await expect(fetchUser(123)).rejects.toMatchObject({
name: 'NetworkError',
message: 'timeout'
});
});</p>手动 await + try/catch(需确保抛出错误)
仅当需要在 reject 后做额外逻辑(如清理、多断言)时才用。但必须注意:catch 中不能只 console.log,而要 显式 throw 或调用 expect().toThrow,否则测试会误认为成功通过:
立即学习“Java免费学习笔记(深入)”;
- ❌ 错误写法(测试会通过,即使函数没 reject):
try { await fn(); } catch (e) { console.log(e); } - ✅ 正确写法:
try { await fn(); expect(true).toBe(false); } catch (e) { expect(e).toBeInstanceOf(ValidationError); }
避免 .catch() 后不 re-throw
不要在测试代码里写 fn().catch(e => { /* 处理 */ }),因为这会吞掉 rejection,测试框架无法感知异常,可能造成“假通过”。如果业务逻辑本身用了 .catch,测试时应确保其行为可观察(例如返回特定值或修改状态),而非依赖未捕获的 reject。
注意测试运行器的 rejection 处理策略
某些环境(如原生 Node.js test runner 或旧版 Jest)对未 await 的 rejected Promise 更敏感。确保:
- 所有 async 测试函数都 return 或 await 对应的 Promise
- 不遗漏 await —— expect(Promise.reject(...)) 不会生效,必须是 await expect(...)
- Jest 中可临时启用 jest.unstable_Configure({ unhandledRejections: 'warn' }) 辅助定位漏处理的 reject


















