Jest测试Redux Saga图片流fetch请求时如何Mock接口响应
Redux Saga 中返回图片流的Fetch请求Mock单测方案
不需要构造真实的图片可读流,只要按saga执行逻辑逐层Mock依赖即可,全程用单测框架自带的Mock能力就能实现,不需要额外引入第三方库。
前置Mock准备
测试环境默认没有fetch和URL.createObjectURL的浏览器实现,先在测试文件开头全局Mock这两个方法,避免运行报错:
import { call, put } from 'redux-saga/effects'; import { getImageSaga } from '@/sagas/image'; // 替换成你的saga实际路径 import { GET_IMAGE_API } from '@/constants/api'; // 替换成接口常量实际路径 import { getImageSuccess, getImageError } from '@/actions/image'; // 替换成action实际路径 beforeAll(() => { global.fetch = jest.fn(); // 固定返回一个测试用的假blob地址 global.URL.createObjectURL = jest.fn(() => 'mock-image-object-url'); }); // 每个用例执行后清空Mock调用记录,避免用例间互相干扰 afterEach(() => { jest.clearAllMocks(); });
成功场景测试用例
Generator函数的单测只需要按执行顺序逐步传入Mock值,校验每一步的输出effect是否符合预期即可:
- 第一个yield节点是fetch调用,先校验传入fetch的参数是否正确,再给生成器传入一个Mock的response对象
- 这个Mock的response不需要实现完整的Response接口,只需要加一个返回假Blob的
blob()方法就行 - 第二个yield节点是blob()调用,传入提前构造的假Blob对象,推进执行
- 最后校验是否正确派发了成功action,携带的对象URL和Mock返回值一致
对应代码:
test('请求成功时应该派发getImageSuccess动作,携带生成的图片blob地址', () => { // 构造假的图片Blob,不需要真实图片内容,随便传点字符串标记即可 const mockImageBlob = new Blob(['test-fake-image'], { type: 'image/jpeg' }); // Mock fetch返回的响应对象,只实现用到的blob方法 const mockFetchResponse = { blob: jest.fn(() => Promise.resolve(mockImageBlob)) }; fetch.mockResolvedValue(mockFetchResponse); const saga = getImageSaga(); // 校验fetch调用参数 expect(saga.next().value).toEqual(call(fetch, GET_IMAGE_API, { headers: { Accept: 'image/jpeg' }, method: 'GET' })); // 传入Mock响应,推进到blob调用步骤 const blobEffect = saga.next(mockFetchResponse).value; expect(mockFetchResponse.blob).toHaveBeenCalledTimes(1); expect(blobEffect).resolves.toEqual(mockImageBlob); // 传入Mock Blob,推进到createObjectURL步骤 saga.next(mockImageBlob); expect(URL.createObjectURL).toHaveBeenCalledWith(mockImageBlob); // 校验最终派发的成功动作 expect(saga.next().value).toEqual(put(getImageSuccess('mock-image-object-url'))); // 校验saga执行完毕 expect(saga.next().done).toBe(true); });
异常场景测试用例
只需要在对应yield节点抛出错误,校验是否派发错误动作即可,比如网络错误场景:
test('请求失败时应该派发getImageError动作,携带错误对象', () => { const mockNetworkError = new Error('image request failed'); fetch.mockRejectedValue(mockNetworkError); const saga = getImageSaga(); // 走到fetch调用节点 saga.next(); // 模拟fetch抛出异常 expect(saga.throw(mockNetworkError).value).toEqual(put(getImageError(mockNetworkError))); // 校验saga执行完毕 expect(saga.next().done).toBe(true); });
如果要覆盖blob解析失败的场景,只需要把mockFetchResponse.blob改成返回rejected状态的Promise即可,逻辑和上面完全一致。
如果你用了
redux-saga-test-plan这类saga测试辅助库,不需要手动一步步调用next推进生成器,只需要提前配置好fetch的Mock返回值,直接运行saga断言最终的effect结果即可,核心Mock逻辑和上述方案没有区别。
内容的提问来源于stack exchange,提问作者Sengiria
相关产品推荐
相关产品推荐

