You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 01:15:39