如何在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
相关产品推荐
相关产品推荐

