React组件Axios调用单元测试中Sinon Stub未生效问题
使用Sinon Sandbox Mock Axios测试React组件的API调用场景
你是不是在测试React组件里setState回调中调用Axios发起请求的逻辑呀?我看你已经用Sinon Sandbox写了基础的Stub,但可能需要调整几个点才能让测试准确覆盖到目标代码,下面给你梳理下关键步骤和注意事项:
先看你当前的Stub代码
你现在写的是Stub Axios的get方法:
sandbox1 = sandbox.create(); const resolved = new Promise((r) => r([{ id: 1, name: 'PetA' }, { id: 2, name:'PetB' }])); sandbox1.stub(axios, 'get').returns(resolved);
但你要测试的代码里调用的是axios(req)(直接调用Axios默认函数),不是axios.get,所以这个Stub不会匹配到你的请求调用,得调整Stub目标。
调整Stub匹配axios(req)调用
因为axios(req)是调用Axios的默认导出函数,所以要把Stub目标改成Axios默认函数本身,同时模拟真实的Axios响应结构(Axios响应会包裹在data字段里):
// 创建模拟成功响应的Promise const mockResponse = Promise.resolve({ data: [{ id: 1, name: 'PetA' }, { id: 2, name:'PetB' }] }); // Stub Axios默认函数 sandbox1.stub(axios, 'default').returns(mockResponse); // 如果你的导入方式是import axios from 'axios',也可以直接这么写: // sandbox1.stub(axios).returns(mockResponse);
处理React异步setState的测试时机
setState的回调是异步执行的,测试时必须等待回调执行完毕再做断言。这里推荐用async/await配合测试库的等待方法,比如React Testing Library的waitFor,或者Enzyme里的setImmediate:
示例测试用例(以React Testing Library为例)
import { render, screen, waitFor } from '@testing-library/react'; import YourComponent from './YourComponent'; import axios from 'axios'; import sinon from 'sinon'; describe('YourComponent', () => { let sandbox1; beforeEach(() => { sandbox1 = sinon.createSandbox(); }); afterEach(() => { sandbox1.restore(); // 清理Sandbox,避免污染其他测试 }); test('setState回调中调用Axios请求成功后更新状态', async () => { // 1. 准备Mock数据和Stub const mockData = [{ id: 1, name: 'PetA' }, { id: 2, name:'PetB' }]; sandbox1.stub(axios, 'default').resolves({ data: mockData }); // 2. 渲染组件并触发触发setState的动作(比如点击按钮) render(<YourComponent />); screen.getByText('触发请求').click(); // 3. 等待异步操作完成并断言 await waitFor(() => { // 断言Axios被调用了一次 expect(axios.default.calledOnce).toBe(true); // 断言UI渲染结果(用状态驱动的UI更易断言) expect(screen.getByText('PetA')).toBeInTheDocument(); expect(screen.getByText('PetB')).toBeInTheDocument(); }); }); });
额外:模拟请求失败场景
如果要测试错误处理逻辑,只需要Stub返回rejected的Promise即可:
sandbox1.stub(axios, 'default').rejects(new Error('请求超时')); // 然后断言组件是否正确处理错误,比如显示错误提示 await waitFor(() => { expect(screen.getByText('请求超时')).toBeInTheDocument(); });
内容的提问来源于stack exchange,提问作者Sagar Kalburgi
相关产品推荐
相关产品推荐

