JavaScript中async函数单元测试覆盖率可达100%,关键在于测试函数声明为async、正确mock异步依赖(如success/reject/error)、覆盖所有执行路径(if分支、try/catch、early return)并清理副作用。

JavaScript 中 async 函数的单元测试覆盖率,关键不在于“能否测”,而在于“是否正确模拟异步行为、是否覆盖所有执行路径(包括成功、失败、边界条件)”。只要用对工具和写法,async 函数的覆盖率完全可以和同步函数一样高。
用 Jest 正确声明 async 测试用例
Jest 原生支持 async/await,但必须让测试函数本身是 async 的,否则 await 不会等待,导致断言提前执行、覆盖率统计异常(例如 `then` 回调未被计入)。
✅ 正确写法:
- 测试函数加 async 关键字
- 用 await 调用被测 async 函数
- 避免混用
.then()和await(易出错)
test('fetchUser 返回有效用户', async () => {
const user = await fetchUser(123);
expect(user.name).toBe('Alice');
});模拟异步依赖(如 API 调用)
真实请求无法保证稳定性,也不利于分支覆盖。必须用 mock 控制返回值和错误,才能测到 resolve/reject 分支、超时、网络异常等场景。
立即学习“Java免费学习笔记(深入)”;
✅ 推荐做法:
- 用
jest.mock()或jest.fn().mockResolvedValue()模拟 Promise 行为 - 分别写用例:mock 成功响应、mock
reject、mock 抛出异常 - 确保 catch 块、.catch()、try/catch 内部逻辑都被执行到
test('fetchUser 失败时返回空对象', async () => {
(axios.get as jest.Mock).mockRejectedValue(new Error('Network error'));
const result = await fetchUser(123);
expect(result).toEqual({});
});覆盖 try/catch、条件分支与早期返回
async 函数里常有 if 判断、early return、嵌套 await,这些都会影响语句/分支覆盖率。工具(如 Jest + Istanbul)只统计实际执行的代码行,没走到的分支不会被覆盖。
✅ 必须覆盖的典型路径:
- if 条件为 true / false 两种情况(例如参数校验)
- try 块正常执行 ✅
- catch 块触发(需 mock reject 或 throw)✅
- await 后续逻辑(比如处理结果、二次调用)✅
npm test -- --coverage --collectCoverageFrom="src/**/*.{js,ts}" 查看具体哪行未覆盖,针对性补测试。
注意顶层 await 和副作用清理
如果 async 函数启动了定时器、监听事件或发起长连接,测试后需主动清理,否则可能干扰后续用例,甚至导致 Jest 超时退出(影响覆盖率报告生成)。
✅ 安全做法:
- 在
afterEach或jest.clearAllTimers()清理 timer - mock 全局 fetch / setTimeout 并在测试后 restore
- 避免在测试中使用
setTimeout(..., 0)等不可控延迟
不复杂但容易忽略:async 函数的覆盖率问题,90% 出在没 await 测试函数、没 mock 异步依赖、没分路径写用例。把这三块做扎实,100% 语句和分支覆盖率完全可行。


















