如何用Jest正确模拟函数?ReactErrorBoundary测试求助
问题分析与解决方案
问题根源
- ErrorBoundary模拟逻辑不合理:原模拟直接在组件函数执行时同步调用
onError和onReset,不符合真实组件的触发逻辑(真实场景下仅在子组件抛出错误时调用onError),且返回非有效React元素可能导致渲染异常。 - 测试断言错误:原测试期望
console.log接收两个参数,但实际onError中仅输出了"Error caught!"一个参数。 - 未处理
window.location.reload:onReset中的页面刷新逻辑会干扰测试,需提前模拟。
解决方案代码修改
1. 修正依赖模拟逻辑
import React from 'react'; import { render } from '@testing-library/react'; import ReactErrorBoundary from '../../components/ReactErrorBoundary'; import { ErrorBoundary } from 'react-error-boundary'; import { logger } from '../../services/logService'; import ErrorPage from '../../components/ErrorPage'; // 模拟日志服务 jest.mock('../../services/logService', () => ({ logger: jest.fn(), })); // 模拟ErrorBoundary组件,存储回调供测试手动触发 jest.mock('react-error-boundary', () => { const React = require('react'); const mockErrorBoundary = jest.fn(({ children, onError, onReset, FallbackComponent }) => { // 将回调挂载到mock函数上,方便测试调用 mockErrorBoundary.onError = onError; mockErrorBoundary.onReset = onReset; // 返回有效React元素,确保组件正常渲染 return <div data-testid="error-boundary">{children}</div>; }); return { ...jest.requireActual('react-error-boundary'), ErrorBoundary: mockErrorBoundary, }; }); // 模拟页面刷新,避免测试中实际刷新页面 jest.spyOn(window.location, 'reload').mockImplementation(() => {});
2. 完善测试用例(含全覆盖率补充)
describe('ReactErrorBoundary', () => { beforeEach(() => { // 重置所有mock调用记录,保证测试独立性 jest.clearAllMocks(); }); test('渲染ErrorBoundary并传入正确的FallbackComponent', () => { render(<ReactErrorBoundary />); expect(ErrorBoundary).toHaveBeenCalledWith( expect.objectContaining({ FallbackComponent: ErrorPage, onError: expect.any(Function), onReset: expect.any(Function), children: undefined, }), {} ); }); test('正确传递子组件给ErrorBoundary', () => { const testChildren = <div>Hello World</div>; render(<ReactErrorBoundary>{testChildren}</ReactErrorBoundary>); expect(ErrorBoundary).toHaveBeenCalledWith( expect.objectContaining({ FallbackComponent: ErrorPage, onError: expect.any(Function), onReset: expect.any(Function), children: testChildren, }), {} ); }); test('触发onError时输出日志并调用logger服务', () => { const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); const testError = new Error("Test error message"); render(<ReactErrorBoundary><div>Test content</div></ReactErrorBoundary>); // 手动触发存储的onError回调 ErrorBoundary.onError(testError); expect(consoleSpy).toHaveBeenCalledWith('Error caught!'); expect(logger).toHaveBeenCalledWith(testError); consoleSpy.mockRestore(); }); test('触发onReset时输出日志并执行页面刷新', () => { const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); render(<ReactErrorBoundary><div>Test content</div></ReactErrorBoundary>); // 手动触发存储的onReset回调 ErrorBoundary.onReset(); expect(consoleSpy).toHaveBeenCalledWith('reloading the page...'); expect(window.location.reload).toHaveBeenCalled(); consoleSpy.mockRestore(); }); });
内容的提问来源于stack exchange,提问作者dxm_scripter
相关产品推荐
相关产品推荐

