javascript单元测试中用async/await编写异步断言,需将测试函数声明为async,await获取返回值后执行expect断言,避免直接用.resolves/.rejects;须mock异步依赖并清理定时器和未完成promise。

在 JavaScript 单元测试中用 async/await 编写异步断言,核心是让测试函数本身是 async,并用 await 等待被测异步操作完成,再执行断言。这样可避免回调地狱、.then() 链式嵌套,代码更接近同步逻辑,可读性高、错误堆栈清晰。
测试函数必须声明为 async
无论使用 Jest、Vitest 还是其他主流测试框架,只要测试涉及异步操作(如 API 调用、定时器、Promise 返回值),测试回调函数需标记为 async,否则 await 无效,且框架可能无法正确等待 Promise 完成。
- Jest 示例:
test('fetches user', async () => { ... }) - Vitest 示例:
it('resolves after delay', async () => { ... }) - 不加
async会导致断言在 Promise 解决前就执行,结果不可靠
直接 await 被测函数,再做 expect 断言
不要把 expect(...).resolves 当默认解法——它只适用于“断言 Promise 本身行为”,而多数场景应等待结果再校验数据内容。清晰的做法是:先 await 获取实际返回值,再对值本身做常规断言。
- ✅ 推荐:
const user = await fetchUser(123); expect(user.name).toBe('Alice'); - ❌ 冗余或掩盖问题:
await expect(fetchUser(123)).resolves.toMatchObject({ name: 'Alice' });(多一层包装,报错时堆栈指向 expect 而非业务逻辑) - 对错误场景也同理:
await expect(() => fetchUser(-1)).rejects.toThrow('Invalid ID');是校验调用抛错;若想验证 reject 的具体 error 值,可await fetchUser(-1).catch(e => expect(e.message).toBe(...))
模拟异步依赖,避免真实 I/O
单元测试要快且稳定,所有外部异步调用(如 fetch、数据库方法)必须 mock。用 jest.mock() 或 Vitest 的 vi.mock() 拦截模块,并返回可控的 Promise。
- Jest 中 mock
fetch:global.fetch = jest.fn(() => Promise.resolve(new Response(JSON.stringify({id: 1, name: 'Bob'})))); - Vitest 中推荐
vi.mock('node-fetch')并导出默认 resolve 函数 - 确保 mock 的 Promise 在
await时按预期 resolve/reject,才能覆盖成功与失败路径
清理副作用:处理未完成的 Promise 或定时器
如果被测代码启动了 setTimeout、setInterval 或未 await 的 Promise(如 fire-and-forget 日志上报),测试可能提前结束导致漏测或内存泄漏。需主动清理。
- Jest:用
jest.useFakeTimers()+jest.runAllTimers()控制时间;用afterEach(() => { jest.clearAllTimers(); }) - Vitest:类似,用
vi.useFakeTimers()和vi.clearAllTimers() - 对未 await 的 Promise,可在测试末尾加
await Promise.resolve()确保微任务队列清空(尤其当代码用了queueMicrotask或Promise.then无返回时)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











