如何使用Jest和Enzyme模拟React组件中的函数
如何用Jest和Enzyme测试React函数组件内部的
func函数 你好呀!针对你在React函数组件中测试内部func函数的需求,我来一步步给你讲清楚怎么实现~
首先先看你的原始组件代码(我稍微调整了格式让它更规范):
import { useState } from 'react'; const App = () => { const [state, setState] = useState(""); const func = (item) => { setState(item); }; return ( <div>{state}</div> ); }; export default App;
你的测试代码已经写了一部分,但因为func是组件内部的函数(函数组件没有实例,没法直接通过wrapper.instance()获取),所以需要用下面两种方式来处理:
方式一:修改组件暴露内部函数(推荐用于直接测试函数逻辑)
如果想直接调用func并验证它的效果,我们可以用forwardRef和useImperativeHandle把内部函数暴露给测试代码:
第一步:更新组件代码
import { useState, forwardRef, useImperativeHandle } from 'react'; // 用forwardRef包裹组件 const App = forwardRef((props, ref) => { const [state, setState] = useState(""); const func = (item) => { setState(item); }; // 把func暴露给外部的ref useImperativeHandle(ref, () => ({ func })); return ( <div>{state}</div> ); }); export default App;
第二步:编写测试代码
import { mount } from 'enzyme'; import App from './App'; import React from 'react'; test("测试func函数能正确更新state", () => { // 创建一个ref来获取组件暴露的方法 const appRef = React.createRef(); const wrapper = mount(<App ref={appRef} />); const testItem = "test"; // 直接调用内部的func函数 appRef.current.func(testItem); // 验证页面上的state是否更新为testItem expect(wrapper.text()).toBe(testItem); });
方式二:模拟useState间接测试(无需修改组件)
如果不想改动组件代码,可以通过模拟React的useState来间接验证func是否正确调用了setState:
测试代码示例
import { mount } from 'enzyme'; import App from './App'; import React from 'react'; test("测试func函数会调用setState", () => { // 模拟setState函数,用来追踪调用情况 const mockSetState = jest.fn(); // 替换React.useState的实现,返回初始值和我们的mock函数 jest.spyOn(React, 'useState').mockImplementation(() => ["", mockSetState]); const wrapper = mount(<App />); // 注意:这种方式下我们没法直接调用func,所以需要给组件添加触发func的交互元素(比如按钮) // 假设你给组件加了一个点击后调用func的按钮:<button onClick={() => func("test")}>更新</button> wrapper.find('button').simulate('click'); // 验证mockSetState是否被正确调用,参数是"test" expect(mockSetState).toHaveBeenCalledWith("test"); // 别忘了恢复useState的原始实现,避免影响其他测试 React.useState.mockRestore(); });
补充说明
- 如果你的
func有更复杂的逻辑(比如处理数据再调用setState),方式一可以更直接地测试函数的输入输出; - 方式二更适合测试函数的副作用(比如是否正确调用了setState),不需要改动原有组件结构。
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

