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

如何在Jest与Enzyme中Mock API并测试Fetch请求?

如何Mock Fetch调用测试你的API封装方法

别担心,Mock Fetch调用其实没那么复杂,我来一步步教你怎么做~首先先明确你的代码结构:

你的API封装静态方法

static sendJsonRequest(address, action, requestType, jsonData, queryParams, successCallback, errorCallback){ 
  var finalURL = Client.getServiceURL( address, action, queryParams); 
  fetch(finalURL, { 
    method: requestType, 
    headers: { 
      'content-type': 'application/json; charset=utf-8', 
      'Authorization': 'Bearer ' + localStorage.getItem("access_token"), 
      'pragma': 'no-cache', 
      'cache-control': 'no-cache' 
    }, 
    body: String(requestType).toLowerCase() === "get" ? undefined : JSON.stringify(jsonData) 
  }) 
  .then(function(response) { 
    if (!response.ok) { 
      throw Error(response.statusText); 
    } 
    return response.json(); 
  }) 
  .then(function(jsonObj) { 
    successCallback(jsonObj); 
  }) 
  .catch(function(err) { 
    errorCallback(err); 
  }); 
}

组件中的调用方式

componentDidMount(){ 
  this.getPermissions(); 
} 
getPermissions(){ 
  this.setState({ Permissions_DATA: [] }); 
  var permissionData = {userName: "xyz", resourceId : localStorage.getItem("target_resource_id")}; 
  Client.sendJsonRequest("authData", "getPermData", "POST", permissionData, "", this.handleGetPermissions, this.handleError); 
} 
handleGetPermissions(response){ 
  // 处理逻辑
} 
handleError(e) { 
  // 错误处理
}

接下来我会用Jest(React项目最常用的测试框架)演示两种Mock Fetch的方式,你可以根据自己的习惯选择:


方法一:手动Mock全局Fetch

这种方式不需要额外安装依赖,直接在测试文件里覆盖全局的fetch对象:

步骤1:Mock所有依赖项

你的API方法依赖localStorage和Client.getServiceURL,先把它们Mock掉,避免测试依赖真实环境:

// Mock localStorage的getItem方法,返回测试用的固定值
Storage.prototype.getItem = jest.fn((key) => {
  if (key === "access_token") return "test-token-123";
  if (key === "target_resource_id") return "test-resource-456";
});

// Mock Client.getServiceURL,让它返回一个可预测的测试URL
Client.getServiceURL = jest.fn((address, action) => `https://test-api.com/${address}/${action}`);

步骤2:编写测试用例

import { render, waitFor } from '@testing-library/react';
import YourComponent from './YourComponent';

describe('YourComponent API Calls', () => {
  let handleGetPermissionsMock;
  let handleErrorMock;

  beforeEach(() => {
    // 重置所有Mock,避免测试间的污染
    jest.clearAllMocks();
    
    // Mock组件的回调函数,方便验证是否被触发
    handleGetPermissionsMock = jest.fn();
    handleErrorMock = jest.fn();

    // 模拟全局fetch的成功响应
    global.fetch = jest.fn(() => 
      Promise.resolve({
        ok: true,
        json: () => Promise.resolve({ permissions: ["read", "write"] })
      })
    );
  });

  it('should call fetch with correct parameters when component mounts', async () => {
    // 渲染组件
    render(<YourComponent />);

    // 等待异步的fetch调用完成
    await waitFor(() => expect(global.fetch).toHaveBeenCalled());

    // 验证getServiceURL的调用参数是否正确
    expect(Client.getServiceURL).toHaveBeenCalledWith("authData", "getPermData", "");
    const expectedURL = "https://test-api.com/authData/getPermData";

    // 验证fetch的请求配置是否符合预期
    expect(global.fetch).toHaveBeenCalledWith(expectedURL, {
      method: "POST",
      headers: {
        'content-type': 'application/json; charset=utf-8',
        'Authorization': 'Bearer test-token-123',
        'pragma': 'no-cache',
        'cache-control': 'no-cache'
      },
      body: JSON.stringify({ userName: "xyz", resourceId: "test-resource-456" })
    });
  });

  it('should trigger success callback when fetch succeeds', async () => {
    // 渲染组件并替换它的回调方法
    const { instance } = render(<YourComponent />);
    instance.handleGetPermissions = handleGetPermissionsMock;

    // 手动调用getPermissions方法
    instance.getPermissions();

    await waitFor(() => expect(handleGetPermissionsMock).toHaveBeenCalled());
    // 验证回调的参数是否正确
    expect(handleGetPermissionsMock).toHaveBeenCalledWith({ permissions: ["read", "write"] });
  });

  it('should trigger error callback when fetch fails', async () => {
    // 修改fetch的Mock,返回失败响应
    global.fetch = jest.fn(() => 
      Promise.resolve({
        ok: false,
        statusText: "Unauthorized"
      })
    );

    const { instance } = render(<YourComponent />);
    instance.handleError = handleErrorMock;

    instance.getPermissions();

    await waitFor(() => expect(handleErrorMock).toHaveBeenCalled());
    expect(handleErrorMock).toHaveBeenCalledWith(Error("Unauthorized"));
  });
});

方法二:使用jest-fetch-mock简化操作

jest-fetch-mock是专门为Jest设计的Fetch Mock工具,能让代码更简洁:

步骤1:安装依赖

npm install jest-fetch-mock --save-dev

步骤2:配置Jest

在项目根目录的jest.config.js里添加:

module.exports = {
  setupFilesAfterEnv: ['./jest.setup.js']
}

然后创建jest.setup.js文件,启用Fetch Mock:

import fetchMock from 'jest-fetch-mock';
fetchMock.enableMocks();

步骤3:编写测试用例

import fetchMock from 'jest-fetch-mock';
import { waitFor } from '@testing-library/react';
import Client from './Client';

describe('Client.sendJsonRequest', () => {
  beforeEach(() => {
    // 重置Mock
    fetchMock.resetMocks();
    
    // Mock依赖项
    Storage.prototype.getItem = jest.fn((key) => {
      if (key === "access_token") return "test-token-123";
      if (key === "target_resource_id") return "test-resource-456";
    });
    Client.getServiceURL = jest.fn(() => "https://test-api.com/authData/getPermData");
  });

  it('calls fetch correctly and triggers success callback', async () => {
    // 模拟成功的API响应
    fetchMock.mockResponseOnce(JSON.stringify({ permissions: ["read"] }), { status: 200 });
    
    const handleSuccess = jest.fn();
    Client.sendJsonRequest(
      "authData", 
      "getPermData", 
      "POST", 
      { userName: "xyz", resourceId: "test-resource-456" }, 
      "", 
      handleSuccess, 
      jest.fn()
    );

    await waitFor(() => expect(handleSuccess).toHaveBeenCalled());
    // 验证fetch的调用参数
    expect(fetchMock).toHaveBeenCalledWith("https://test-api.com/authData/getPermData", expect.objectContaining({
      method: "POST",
      headers: expect.objectContaining({
        'Authorization': 'Bearer test-token-123'
      })
    }));
    // 验证回调的参数
    expect(handleSuccess).toHaveBeenCalledWith({ permissions: ["read"] });
  });

  it('triggers error callback on failed fetch', async () => {
    // 模拟失败的API响应
    fetchMock.mockResponseOnce("", { status: 401, statusText: "Unauthorized" });
    
    const handleError = jest.fn();
    Client.sendJsonRequest(
      "authData", 
      "getPermData", 
      "POST", 
      {}, 
      "", 
      jest.fn(), 
      handleError
    );

    await waitFor(() => expect(handleError).toHaveBeenCalled());
    expect(handleError).toHaveBeenCalledWith(Error("Unauthorized"));
  });
});

关键注意点

  • 一定要Mock所有外部依赖:比如localStorage、Client.getServiceURL,否则测试会受到真实环境的影响。
  • 用waitFor或者async/await等待异步操作完成,避免测试提前结束导致断言失败。
  • 每次测试前重置Mock,保证测试之间相互独立。

内容的提问来源于stack exchange,提问作者rahul

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:45:00