异步测试核心是验证触发、时序与副作用,而非单纯等待;Jest为首选工具,支持async/await、fake timers及请求mock;模板覆盖async函数、回调函数、事件触发和防抖节流;需注意清理mock、避免混用done与return、捕获reject、拦截网络请求。

明确测试目标:区分异步行为与结果验证
异步测试不是“等代码跑完再断言”,而是确认异步逻辑按预期触发、时序正确、副作用可控。重点验证三件事:回调是否被调用、Promise 是否 resolve/reject、副作用(如 API 调用、状态更新)是否发生且参数正确。
选对测试工具链:Jest 是当前最简实践方案
Jest 原生支持 async/await、mock timers 和 自动清理 mock,无需额外配置即可覆盖多数场景:
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
- 测试 Promise:直接 return promise 或用 async/await
- 测试定时器(setTimeout/setInterval):用 jest.useFakeTimers() + jest.runAllTimers()
- 测试 fetch 或 axios:用 jest.mock('node-fetch') 或 jest.mock('axios') 拦截请求
写法直给:4 类高频异步代码的测试模板
1. 测试 async 函数
```js
test('fetchUser 返回用户数据', async () => {
mockFetch.mockResolvedValue({ json: () => ({ id: 1, name: 'Alice' }) });
const user = await fetchUser(1);
expect(user.name).toBe('Alice');
});
```
2. 测试带回调的函数(如 Node.js 风格)
```js
test('readFile 调用 callback 并传入正确数据', (done) => {
mockReadFile.mockImplementation((path, cb) => cb(null, 'content'));
readFile('/tmp/test.txt', (err, data) => {
expect(err).toBeNull();
expect(data).toBe('content');
done(); // 必须调用,否则 Jest 超时
});
});
```
3. 测试事件触发(如 EventEmitter)
```js
test('emitter 触发 data 事件并传递 payload', (done) => {
const emitter = new EventEmitter();
emitter.once('data', (payload) => {
expect(payload).toEqual({ ok: true });
done();
});
emitter.emit('data', { ok: true });
});
```
4. 测试防抖/节流函数
```js
test('debounceFn 在延迟后执行且只执行一次', () => {
jest.useFakeTimers();
const fn = jest.fn();
const debounced = debounce(fn, 300);
debounced();
debounced();
debounced();
jest.runAllTimers(); // 快进所有定时器
expect(fn).toHaveBeenCalledTimes(1);
});
```
避坑清单:不写注释就容易翻车的细节
- 忘记清理 mock:每个 test 末尾加 mockFn.mockClear(),或在 beforeEach 统一重置
- 混用 done 和 return:二者二选一,同时用会报错或漏测
- 未处理 reject:Promise 测试中必须 catch 错误,或用 expect(() => fn()).rejects.toThrow()
- 真实网络未拦截:本地测试务必 mock fetch/axios,否则依赖外部服务且不可控










