React单元测试中如何使用jest-fetch-mock模拟fetch响应
Jest中模拟组件fetch请求响应的实现方案
你已经完成了jest-fetch-mock的全局挂载,测试时只需要在组件渲染前配置好对应请求的mock规则,同时处理好异步断言即可,具体写法如下:
前置准备
建议在测试文件的钩子中先配置mock重置逻辑,避免多个测试用例之间的mock状态互相干扰:
// 每个测试用例执行前清空所有mock规则、调用记录 beforeEach(() => { fetch.resetMocks(); });
场景1:模拟接口正常返回(200响应)
因为你的接口请求写在useEffect中,组件挂载就会自动触发,所以必须在渲染组件之前配置好mock响应规则,否则请求触发时mock还未生效。
以下是和React Testing Library搭配的完整测试用例示例:
import { render, waitFor, screen } from '@testing-library/react'; import Component from './Component'; test('组件挂载时请求接口,成功后正确更新状态', async () => { // 1. 定义和接口返回结构一致的mock数据 const mockRes = { videos: [ { id: 1, name: '测试视频1' }, { id: 2, name: '测试视频2' } ] }; // 2. 配置单次fetch请求的响应规则:下一次fetch触发时返回该结果 fetch.mockResponseOnce(JSON.stringify(mockRes), { status: 200, headers: { 'Content-Type': 'application/json' } }); // 3. 渲染组件,自动触发useEffect中的fetch请求 render(<Component />); // 4. 异步断言:等待请求完成后校验逻辑 // 先校验请求是否按预期发起 expect(fetch).toHaveBeenCalledTimes(1); expect(fetch).toHaveBeenCalledWith('url'); // 再校验状态更新后的渲染结果,比如等视频元素加载 await waitFor(() => { expect(screen.getByText('测试视频1')).toBeInTheDocument(); expect(screen.getByText('测试视频2')).toBeInTheDocument(); }); });
场景2:模拟接口请求异常(测试catch分支)
如果要覆盖请求报错的逻辑,可以用mockRejectOnce模拟请求抛出错误:
test('接口请求失败时打印错误日志', async () => { // 监听console.error,拦截错误打印避免测试控制台输出冗余信息 const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); const mockErr = new Error('网络请求超时'); // 配置下一次fetch直接抛出错误 fetch.mockRejectOnce(mockErr); render(<Component />); await waitFor(() => { expect(errorSpy).toHaveBeenCalledWith(mockErr); }); // 恢复console的原始实现 errorSpy.mockRestore(); });
注意事项
- 不要在
render组件之后再配置mock规则,否则useEffect里的请求会先触发,拿不到你配置的mock响应 - 所有涉及异步请求的断言都要加等待逻辑,可以用
waitFor包裹,或者用Testing Library自带的findBy*系列查询方法(默认自带1000ms超时等待),不要在render之后直接同步断言,否则会因为请求还没返回导致断言失败 - 如果一个用例里有多次连续的fetch请求,可以链式调用
mockResponseOnce,每调用一次对应一次请求的返回结果
内容的提问来源于stack exchange,提问作者Ajay S
相关产品推荐
相关产品推荐

