如何用JEST/Enzyme为带componentDidMount与Redux connect的React组件写单测
React Redux 连接组件单元测试方案
前置调整
先给原有组件新增命名导出,方便单独测试未被Redux包裹的原始组件:
// 新增命名导出,测试内部逻辑时直接导入这个即可 export class MyComponent extends Component { componentDidMount = () => { // 原有逻辑 } handleSignIn = (e) => { // 原有逻辑 } render() { return ( <div> <form onSubmit={this.handleSignIn}> <Input type="text" name="inputText" placeholder="Text" autoFocus required /> </form> </div> ); } } const updateProps = (dispatch) => { return { // 原有绑定的dispatch方法 }; }; export default connect(null, updateProps)(MyComponent);
测试用例编写思路
测试分两类场景覆盖全量逻辑:
- 原始组件内部逻辑测试:无需依赖Redux,手动传入需要的props即可,覆盖生命周期、事件处理、渲染逻辑
- 连接组件逻辑测试:验证Redux的dispatch绑定逻辑是否符合预期,确保updateProps返回的方法正确挂载到组件props上
测试代码示例(基于Jest + React Testing Library)
import { render, screen, fireEvent } from '@testing-library/react'; import { Provider } from 'react-redux'; import configureMockStore from 'redux-mock-store'; // 导入原始组件和连接后的组件 import ConnectedMyComponent, { MyComponent } from './MyComponent'; const mockStore = configureMockStore(); // 第一部分:测试原始组件逻辑 describe('原始组件 MyComponent 测试', () => { // 测试componentDidMount逻辑 it('componentDidMount 触发时执行预期逻辑', () => { // mock componentDidMount里用到的props方法 const mockMountAction = jest.fn(); render(<MyComponent mockMountAction={mockMountAction} />); // 断言方法被调用 expect(mockMountAction).toHaveBeenCalledTimes(1); }); // 测试表单提交逻辑 it('表单提交时触发handleSignIn执行预期逻辑', () => { const mockSignIn = jest.fn(); render(<MyComponent signIn={mockSignIn} />); // 模拟输入内容 fireEvent.change(screen.getByRole('textbox'), { target: { value: '测试内容' } }); // 模拟提交表单 fireEvent.submit(screen.getByRole('form')); // 断言提交逻辑被正确触发 expect(mockSignIn).toHaveBeenCalledWith('测试内容'); }); // 测试渲染是否正常 it('渲染出必填的文本输入框', () => { render(<MyComponent />); const input = screen.getByRole('textbox'); expect(input).toBeInTheDocument(); expect(input).toBeRequired(); }); }); // 第二部分:测试Redux连接逻辑 describe('Redux 连接组件测试', () => { let store; beforeEach(() => { store = mockStore({}); // mock store的dispatch方法 store.dispatch = jest.fn(); }); it('updateProps返回的方法正确挂载到组件props上', () => { const { result } = render(<ConnectedMyComponent />, { wrapper: ({ children }) => <Provider store={store}>{children}</Provider> }); // 假设updateProps返回了submitForm方法,调用该方法验证是否触发dispatch result.current.props.submitForm('测试内容'); // 断言dispatch被正确调用 expect(store.dispatch).toHaveBeenCalledWith(/* 替换为你预期触发的action对象 */); }); });
可选优化
如果你使用Enzyme作为测试工具,可以用dive方法直接拿到connect包裹的原始组件实例,不用额外导出原始组件也能测试内部逻辑。
内容的提问来源于stack exchange,提问作者Bhautik
相关产品推荐
相关产品推荐

