JavaScript测试中替换全局fetch的核心是用模拟函数覆盖window.fetch并在测试后恢复,常用方式包括Jest手动mock、Jest mockImplementation按条件响应、msw拦截真实请求,需注意mock Response方法、Node环境适配及跨测试污染防护。

在 JavaScript 测试中替换全局 fetch,核心是**用可控制的模拟函数覆盖 window.fetch(或 globalThis.fetch)**,并在测试结束后恢复原实现,避免污染其他测试。常用方式有手动 mock、Jest 自带 mock、或使用 msw(Mock Service Worker) 等工具。
1. 使用 Jest 手动 mock 全局 fetch
Jest 默认会自动将 fetch 挂载到 global 上,你可以直接重写它:
- 在测试文件顶部或
beforeEach中覆盖:
global.fetch = jest.fn(); - 返回 Promise,模拟成功响应:
global.fetch.mockResolvedValueOnce(new Response(JSON.stringify({ id: 1 }), { status: 200 })); - 模拟失败(如网络错误):
global.fetch.mockRejectedValueOnce(new TypeError('Failed to fetch')); - 测试后清理(推荐在
afterEach中):
global.fetch.mockReset(); // 或 .mockRestore() 恢复原始 fetch
2. 使用 Jest 的 automock + mockImplementation
更清晰的方式是显式 mock 并定义行为逻辑:
- 在
beforeEach中设置:
global.fetch = jest.fn().mockImplementation((url) => {
if (url.includes('/api/users')) {
return Promise.resolve(new Response('[{"id":1}]', { headers: { 'Content-Type': 'application/json' } }));
}
return Promise.reject(new Error('Not mocked'));
}); - 这样可以按 URL、method、body 等条件差异化响应,适合复杂场景。
3. 使用 msw(Mock Service Worker)——推荐用于 E2E 或集成测试
msw 不替换 fetch,而是拦截真实网络请求,在 Service Worker 层模拟响应,更接近真实环境:
立即学习“Java免费学习笔记(深入)”;
- 安装:
npm install msw --save-dev - 定义 handlers(如
src/mocks/handlers.js):
import { rest } from 'msw';
export const handlers = [
rest.get('/api/posts', (req, res, ctx) => {
return res(ctx.status(200), ctx.json([{ id: 1, title: 'Test' }]));
}),
]; - 在测试中启动 worker:
import { setupServer } from 'msw/node';
import { handlers } from './mocks/handlers';
const server = setupServer(...handlers);
beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers()); - 所有
fetch、axios等请求都会被拦截,无需修改代码逻辑。
4. 注意事项与常见陷阱
-
不要只 mock 返回值,也要 mock Response 方法:比如
res.json()、res.text()需要返回 Promise,否则业务代码可能报错;可用jest.fn().mockResolvedValue(...)模拟它们。 -
Node 环境无原生 fetch:若用 Node(如 Jest 默认环境),需先安装
node-fetch并赋值给global.fetch,或启用jest-environment-jsdom。 -
避免跨测试污染:始终在
beforeEach设置 mock,在afterEach清理(.mockClear()或.mockReset())。 -
检查调用参数:用
expect(fetch).toHaveBeenCalledWith(...)验证 URL、options 是否符合预期。
不复杂但容易忽略:mock 的本质是控制输入输出,关键是让被测代码“感觉不到区别”,同时让你能断言交互是否正确。选 Jest mock 还是 msw,取决于你测的是单元逻辑(前者轻量)还是真实请求流(后者更真实)。


















