generator函数返回迭代器对象而非promise,测试重点是驱动其执行并断言yield值、返回结果及错误处理行为。

Generator 函数本身不直接返回 Promise,但配合 co、redux-saga 或手动执行器(如 runGenerator)时,常用于异步流程控制。要对它写异步测试,关键不是“测试 generator 返回值本身”,而是测试它**被正确驱动后产生的行为**——比如是否 yield 了预期的 effect、是否在 mock 异步调用后得到正确结果。
明确 generator 的测试目标
Generator 函数(如 function* fetchUser() { yield call(api.getUser, 1); })返回的是迭代器对象,不是最终值。测试重点通常是:
- 它是否按顺序 yield 了正确的 effect(如
{ type: 'CALL', fn: api.getUser, args: [1] }) - 当模拟外部调用(如
api.getUser)返回值后,generator 是否能继续执行并 return 正确结果 - 错误路径是否被正确捕获和处理(如 try/catch + yield 后续逻辑)
用 jest + 手动执行器测试(无额外库)
适合轻量场景。核心是:调用 next() / throw() 模拟 yield 和异步回调。
function* loadProfile(userId) {
const user = yield fetch(`/api/users/${userId}`);
return { profile: user };
}
<p>// 测试
test('loadProfile yields fetch and returns profile', () => {
const gen = loadProfile(123);</p><p>// 第一次 next → yield fetch(...)
expect(gen.next().value).toEqual(fetch('/api/users/123'));</p><p>// 模拟 fetch 成功返回
const mockResponse = { id: 123, name: 'Alice' };
expect(gen.next(mockResponse).value).toBeUndefined(); // 已完成
expect(gen.return()).toEqual({ value: { profile: mockResponse }, done: true });
});
</p>
用 co 或 redux-saga/test-utils 简化断言
如果项目已用 co 封装 generator(返回 Promise),可直接 await 测试:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
const co = require('co');
<p>function* asyncTask() {
const data = yield Promise.resolve('done');
return data.toUpperCase();
}</p><p>test('co-wrapped generator resolves correctly', async () => {
const result = await co(asyncTask);
expect(result).toBe('DONE');
});
</p>
若用 redux-saga,推荐使用其官方 testSaga:
import { testSaga } from 'redux-saga-test-plan';
import { call, put } from 'redux-saga/effects';
<p>function* saga() {
const res = yield call(api.fetchUser, 1);
yield put({ type: 'USER_LOADED', payload: res });
}</p><p>test('saga calls api and dispatches action', () => {
testSaga(saga)
.next()
.call(api.fetchUser, 1)
.next({ id: 1, name: 'Bob' })
.put({ type: 'USER_LOADED', payload: { id: 1, name: 'Bob' } })
.finish()
.isDone();
});
</p>
Mock 异步依赖,隔离测试
generator 内部的 fetch、setTimeout、API 调用必须 mock,否则测试会变慢或不稳定:
- Jest 中用
jest.mock('node-fetch')或全局替换global.fetch = jest.fn() - 对自定义异步函数,直接 mock 其模块导出:
jest.mock('./api', () => ({ getUser: jest.fn().mockResolvedValue(...) })) - 避免在测试中出现
await new Promise(setTimeout),改用jest.runAllTimers()配合jest.useFakeTimers()
不复杂但容易忽略:generator 测试的本质是“控制执行节奏 + 断言中间状态”,而不是等它自动跑完。选对驱动方式(手动 next、co、saga-test-plan),再配好 mock,就能稳稳覆盖异步逻辑。










