如何在jest和@testing-library/react中测试catch代码分支?
单元测试覆盖catch分支的实现方法
要触发resetForm的catch分支,只需要让try代码块内的任意一行同步代码抛出错误即可,以下是两种可落地的测试方案,适配你当前使用的jest 24.9.0 + @testing-library/react 12.1.2版本:
方案1:Mock ref方法主动抛错(最推荐,场景可控)
我们可以主动让someRef.current.resetFormValues调用时抛出错误,精准触发catch分支,测试步骤如下:
- 提前在测试用例的DOM中插入
id="errorDisplayDiv"的元素,避免后续DOM操作提前抛错干扰测试预设 - Mock
setStateAndLogError方法,用于验证catch分支是否被执行 - Mock
someRef的resetFormValues方法,让其调用时主动抛出自定义错误 - 渲染组件后触发Reset按钮的点击事件
- 断言
setStateAndLogError被正确调用,且入参为我们抛出的错误实例
测试代码示例:
import { render, fireEvent } from '@testing-library/react'; import MyComponent from './MyComponent'; import { setStateAndLogError } from './your-module-path'; // mock要验证的catch分支执行方法 jest.mock('./your-module-path', () => ({ ...jest.requireActual('./your-module-path'), setStateAndLogError: jest.fn() })); test('resetForm catch分支被正确覆盖', () => { // 提前插入错误提示DOM const errorDiv = document.createElement('div'); errorDiv.id = 'errorDisplayDiv'; document.body.appendChild(errorDiv); // 自定义错误,用于后续断言 const mockError = new Error('测试触发表单重置错误'); // 若someRef是组件props传入则直接传递mock值,若是内部绑定子组件则mock对应子组件的resetFormValues方法即可 const mockRef = { current: { resetFormValues: jest.fn(() => { throw mockError; }) } }; const { getByText } = render(<MyComponent someRef={mockRef} />); // 触发重置按钮点击 fireEvent.click(getByText('Reset')); // 验证catch分支逻辑执行 expect(setStateAndLogError).toHaveBeenCalledTimes(1); expect(setStateAndLogError).toHaveBeenCalledWith(mockError); // 清理测试插入的DOM document.body.removeChild(errorDiv); });
方案2:DOM缺失触发报错(无需mock ref,实现简单)
如果不想mock ref相关逻辑,可以直接不在测试环境插入id="errorDisplayDiv"的元素,此时document.getElementById("errorDisplayDiv")会返回null,执行div.innerHTML时会自动抛出Cannot set properties of null (setting 'innerHTML')的错误,直接进入catch分支:
import { render, fireEvent } from '@testing-library/react'; import MyComponent from './MyComponent'; import { setStateAndLogError } from './your-module-path'; jest.mock('./your-module-path', () => ({ ...jest.requireActual('./your-module-path'), setStateAndLogError: jest.fn() })); test('resetForm catch分支在DOM缺失时触发', () => { // 确保当前DOM中没有id为errorDisplayDiv的元素 expect(document.getElementById('errorDisplayDiv')).toBeNull(); const mockRef = { current: { resetFormValues: jest.fn() // 这里不用抛错 } }; const { getByText } = render(<MyComponent someRef={mockRef} />); fireEvent.click(getByText('Reset')); expect(setStateAndLogError).toHaveBeenCalledTimes(1); expect(setStateAndLogError).toHaveBeenCalledWith(expect.any(Error)); });
额外注意事项
- 如果
someRef是组件内部声明的未对外暴露的ref,你可以通过jest.mock来mock ref绑定的子组件,让子组件的resetFormValues方法抛错即可 - @testing-library/react 12版本完全兼容
fireEvent事件触发写法,无需额外安装其他依赖
内容的提问来源于stack exchange,提问作者Aditya yadav
相关产品推荐
相关产品推荐

