如何测试React Context内部函数?寻求测试覆盖方案
要覆盖handleClickMenu函数的测试,你需要通过消费Context来调用该函数,并验证它的三个核心行为:更新选中菜单、调用pushBackRoute工具函数、触发路由跳转。以下是具体实现步骤:
步骤1:Mock外部依赖函数
pushBackRoute是外部导入的工具函数,需要在测试中Mock它,方便验证调用情况:
jest.mock('../libs/helpers/backRouteHelper', () => ({ pushBackRoute: jest.fn() }));
步骤2:编写测试用的Context消费组件
创建一个简单组件来消费BottomBarContext,暴露调用handleClickMenu的入口,同时展示当前选中的菜单状态:
import { useContext } from 'react'; import { BottomBarContext } from './BottomBarContext'; const TestConsumer = () => { const { handleClickMenu, selectedMenu } = useContext(BottomBarContext); return ( <div> <span data-testid="selected-menu">{selectedMenu}</span> <button data-testid="trigger-menu-click" onClick={() => handleClickMenu({ name: 'Riwayat', route: '/marketplace/history' })} > 触发菜单点击 </button> </div> ); };
步骤3:完善测试用例
整合上述内容,编写完整测试用例,覆盖handleClickMenu的所有逻辑:
/* eslint-disable jest/prefer-called-with */ import { render, screen, fireEvent } from '@testing-library/react'; import { BottomBarProvider } from './BottomBarContext'; import { useContext } from 'react'; import { BottomBarContext } from './BottomBarContext'; import '@testing-library/jest-dom/extend-expect'; import { pushBackRoute } from '../libs/helpers/backRouteHelper'; const mockHistoryPush = jest.fn(); jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useLocation: () => ({ pathname: '/marketplace' }), useHistory: () => ({ push: mockHistoryPush }) })); // Mock外部工具函数 jest.mock('../libs/helpers/backRouteHelper', () => ({ pushBackRoute: jest.fn() })); // 测试用Context消费组件 const TestConsumer = () => { const { handleClickMenu, selectedMenu } = useContext(BottomBarContext); return ( <div> <span data-testid="selected-menu">{selectedMenu}</span> <button data-testid="trigger-menu-click" onClick={() => handleClickMenu({ name: 'Riwayat', route: '/marketplace/history' })} > 触发菜单点击 </button> </div> ); }; describe('BottomBarProvider', () => { beforeEach(() => { // 重置所有mock调用记录,避免测试用例间干扰 jest.clearAllMocks(); }); it('should render children correctly', () => { const children = <div data-testid="children">Hello, World!</div>; render(<BottomBarProvider>{children}</BottomBarProvider>); expect(screen.getByTestId('children')).toHaveTextContent('Hello, World!'); }); it('should update selectedMenu, call pushBackRoute and trigger history push when handleClickMenu is called', () => { // 渲染Provider和测试消费组件 render( <BottomBarProvider> <TestConsumer /> </BottomBarProvider> ); // 验证初始选中菜单 expect(screen.getByTestId('selected-menu')).toHaveTextContent('Belanja'); // 触发菜单点击事件 fireEvent.click(screen.getByTestId('trigger-menu-click')); // 验证选中菜单已更新 expect(screen.getByTestId('selected-menu')).toHaveTextContent('Riwayat'); // 验证pushBackRoute被正确调用 expect(pushBackRoute).toHaveBeenCalledWith('/marketplace'); // 验证路由跳转被触发 expect(mockHistoryPush).toHaveBeenCalledWith('/marketplace/history'); }); });
关键说明
- 通过测试消费组件,直接访问并触发Context中的
handleClickMenu函数,实现逻辑覆盖。 - 每次测试前重置Mock调用记录,确保测试独立性。
- 分别验证
handleClickMenu的三个核心行为,确保函数逻辑完全符合预期。
内容的提问来源于stack exchange,提问作者Faishal
相关产品推荐
相关产品推荐

