测试 async 函数 reject 行为需用 await expect(fn()).rejects.tothrow(...),不可用 expect(fn).tothrow();须确保函数返回 promise 并 await 断言,否则无法捕获异步拒绝。

在 JavaScript 中测试包含 async 函数和 reject 的异步异常处理,核心是确保能正确捕获 Promise 拒绝(rejected)时的行为,包括 try/catch、.catch() 或错误边界(如 React 中)是否按预期响应。关键在于:**不能用普通 expect(fn).toThrow(),而要用 await expect(fn()).rejects.toThrow(...) 或等价的 Promise 断言方式。**
使用 Jest 测试 async 函数的 reject 行为
Jest 提供了 .rejects 匹配器,专用于断言一个 Promise 被拒绝且携带指定错误。
- 被测函数需返回 Promise(即
async函数或显式返回Promise.reject()) - 测试中必须
await断言,或使用return expect(...).rejects... - 可匹配错误类型、错误消息(支持字符串、正则、对象)
示例:
// utils.jsexport const fetchData = async (url) => {
if (!url) throw new Error('URL is required');
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
};
// utils.test.js
test('fetchData rejects with error when URL is empty', async () => {
await expect(fetchData('')).rejects.toThrow('URL is required');
});
test('fetchData rejects with HTTP error for 404', async () => {
// mock fetch to return 404
global.fetch = jest.fn(() => Promise.resolve({ ok: false, status: 404 }));
await expect(fetchData('/api')).rejects.toThrow('HTTP 404');
});
测试 try/catch 中的异步错误处理逻辑
如果业务代码在 try/catch 内调用异步操作,并对错误做自定义处理(如 fallback、日志、状态更新),测试重点不是“是否抛错”,而是“错误路径是否执行、结果是否符合预期”。
- 模拟异步调用失败(例如 mock 返回 rejected Promise)
- 调用被测函数(它本身可以是同步的,内部含 async)
- 检查副作用:变量赋值、函数调用、返回值、状态变更等
示例:
// loginService.jsexport const login = async (credentials) => {
try {
const token = await api.post('/login', credentials);
return { success: true, token };
} catch (err) {
console.error('Login failed:', err.message);
return { success: false, error: 'Invalid credentials' };
}
};
// loginService.test.js
test('login returns error object when API rejects', async () => {
api.post.mockRejectedValue(new Error('Network error'));
const result = await login({ user: 'a', pass: 'b' });
expect(result).toEqual({ success: false, error: 'Invalid credentials' });
expect(console.error).toHaveBeenCalledWith('Login failed:', 'Network error');
});
避免常见错误
以下写法无法正确捕获异步 reject,需避免:
-
expect(async () => { await fn() }).toThrow()—— 这只测试 async 函数本身不抛同步错误,永远通过 -
expect(fn()).toThrow()——fn()返回 Promise,toThrow不处理 Promise 拒绝 - 忘记
await或return,导致测试不等待 Promise 结束,可能误报“通过” - 用
.resolves断言本该失败的场景(应改用.rejects)
其他测试环境适配
若不用 Jest,原理一致:
-
Vitest:语法完全兼容 Jest,
await expect(fn()).rejects.toThrow(...)可直接使用 -
Mocha + Chai:用
chai-as-promised插件,写成return expect(fn()).to.be.rejectedWith('...') -
纯 Node assert:用
await assert.rejects(fn(), /expected message/)(Node ≥14.17)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











