如何在Jest中Mock全局fetch?解决Mock失效返回真实值问题
问题原因
你的io.js通过import fetch from 'node-fetch'导入了独立的fetch实例,而非使用全局的fetch对象。因此你对global.fetch的mock完全不会被logMovies()调用,这才导致它依然请求真实接口。另外,你的mock返回的是单个对象,但logMovies()会取返回数组的第0项,这也是断言失败的次要原因。
解决方案
下面提供两种可行的mock方式:
方式一:直接mock node-fetch模块(推荐)
修改测试文件,用Jest的jest.mock直接mock整个node-fetch模块:
import { expect, jest } from '@jest/globals'; import { logMovies } from './io'; // Mock node-fetch模块,返回预设的模拟响应 jest.mock('node-fetch', () => jest.fn(() => Promise.resolve({ json: () => Promise.resolve([{ "id": 423638 }]) // 返回数组,匹配logMovies取第0项的逻辑 }) )); // 导入mock后的fetch,用于断言调用情况 import fetch from 'node-fetch'; beforeEach(() => { fetch.mockClear(); }); test("mocks fetch correctly", async () => { const result = await logMovies(); expect(result).toEqual({ "id": 423638 }); // 额外断言fetch是否被正确调用 expect(fetch).toHaveBeenCalledWith("https://api.github.com/users/hadley/orgs"); });
方式二:替换模块内的fetch实例
如果需要保留模块导入fetch的方式,可通过jest.spyOn替换模块内的fetch引用:
- 先修改
io.js,导出fetch以便测试mock:
import path from 'path'; import { promises as fs } from 'fs'; import fetch from 'node-fetch'; // 导出fetch,供测试mock使用 export { fetch }; export async function logMovies() { const response = await fetch("https://api.github.com/users/hadley/orgs"); const movies = await response.json(); return movies[0]; }
- 修改测试文件:
import { expect, jest } from '@jest/globals'; import { logMovies } from './io'; import * as ioModule from './io'; beforeEach(() => { jest.restoreAllMocks(); }); test("mocks fetch correctly", async () => { const mockFetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve([{ "id": 423638 }]) }) ); // 替换io模块内的fetch实例 jest.spyOn(ioModule, 'fetch').mockImplementation(mockFetch); const result = await logMovies(); expect(result).toEqual({ "id": 423638 }); expect(mockFetch).toHaveBeenCalledWith("https://api.github.com/users/hadley/orgs"); });
内容的提问来源于stack exchange,提问作者Naveenkumar
相关产品推荐
相关产品推荐

