如何使用Mocha模拟API调用测试依赖API响应的React组件?
当然可以!完全不用实际调用API就能模拟响应,我来给你详细讲清楚怎么解决这个问题——既搞定fetch is not defined的错误,又能精准控制API返回的数据。
核心思路
你的问题本质是两个:测试环境缺少浏览器的fetch API,以及需要mock异步API的响应。我们可以通过全局mock fetch函数一举解决这两个问题,不用导入isomorphic-fetch。
方案一:手动Mock全局fetch(无需额外库)
如果你不想引入新的依赖,可以直接在测试文件里手动给global对象添加mock版的fetch,还能在不同测试用例里灵活切换成功/失败场景:
import { mount } from 'enzyme'; import YourComponent from './YourComponent'; describe('YourComponent', () => { // 保存原始fetch,测试后恢复 let originalFetch; beforeEach(() => { originalFetch = global.fetch; }); afterEach(() => { global.fetch = originalFetch; }); it('挂载后调用API并设置正确状态', async () => { // 模拟API成功响应 global.fetch = () => Promise.resolve({ ok: true, json: () => Promise.resolve({ username: 'mockUser', email: 'mock@test.com' }) }); // 挂载组件 const wrapper = mount(<YourComponent />); // 等待异步请求完成(让Promise进入resolved状态) await Promise.resolve(); // 更新组件,让异步状态更新同步到Enzyme的wrapper wrapper.update(); // 断言状态是否正确设置 expect(wrapper.state('user')).toEqual({ username: 'mockUser', email: 'mock@test.com' }); }); it('API请求失败时设置错误状态', async () => { // 模拟API失败 global.fetch = () => Promise.reject(new Error('请求超时')); const wrapper = mount(<YourComponent />); await Promise.resolve(); wrapper.update(); expect(wrapper.state('error')).toBe('请求超时'); }); });
方案二:用Sinon做更灵活的Mock(推荐)
如果你需要更强大的mock能力(比如断言fetch是否被调用、调用次数、传入的参数等),可以用sinon这个常用的测试工具库:
- 先安装依赖:
npm install sinon --save-dev
- 测试代码示例:
import { mount } from 'enzyme'; import sinon from 'sinon'; import YourComponent from './YourComponent'; describe('YourComponent', () => { let fetchMock; // 每个测试前创建fetch的mock beforeEach(() => { fetchMock = sinon.stub(global, 'fetch'); }); // 每个测试后恢复原始fetch,避免影响其他测试 afterEach(() => { fetchMock.restore(); }); it('正确调用API地址并处理响应', async () => { // 设置mock返回的响应数据 const mockResponse = { id: 1, name: 'Mock Data' }; fetchMock.resolves({ json: () => Promise.resolve(mockResponse) }); const wrapper = mount(<YourComponent />); await Promise.resolve(); wrapper.update(); // 断言fetch是否被正确调用(检查请求URL) expect(fetchMock.calledWith('https://your-api-url.com/data')).toBe(true); // 断言状态更新正确 expect(wrapper.state('data')).toEqual(mockResponse); }); });
关键注意点
- 异步处理:因为
fetch是异步操作,挂载组件后不能立刻断言状态,需要用await Promise.resolve()或setImmediate等待事件循环完成,再调用wrapper.update()让Enzyme同步组件状态。 - shallow渲染的特殊情况:如果用
shallow渲染,默认不会自动执行componentDidMount,你需要手动调用wrapper.instance().componentDidMount()来触发API调用,之后同样要处理异步更新。
内容的提问来源于stack exchange,提问作者singard
相关产品推荐
相关产品推荐

