如何用Jest mock导入的React Hook并在多测试用例中验证调用
实现方案
你当前写法的核心问题是myMethod对应的jest.fn()定义在jest.mock的工厂函数内部,测试用例无法拿到这个mock函数的引用,自然无法断言调用参数;如果不做状态重置,多个测试用例之间的调用记录还会互相干扰。
可以按照以下步骤改造,既可以校验传入参数,也能保证多个测试用例完全独立:
- 将mock方法的声明提到
jest.mock的外层作用域,让所有测试用例都能拿到这个mock函数的引用 - 在
jest.mock的返回值中使用这个外层声明的mock函数 - 在每个测试用例执行前清空mock函数的调用记录、临时返回值等状态,避免用例间污染
- 触发交互逻辑后,直接通过外层的mock函数引用做调用断言
完整测试代码示例
import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import MyComponent from '对应组件路径'; // 外层声明mock函数,所有用例可直接访问 const mockMyMethod = jest.fn(); // mock自定义Hook jest.mock('hooks/useMyHook', () => ({ useMyHook: () => ({ myMethod: mockMyMethod, // Hook有其他返回值直接在这里补充即可 }) })); describe('<MyComponent />', () => { // 每个用例执行前重置mock状态,保证用例完全独立 beforeEach(() => { mockMyMethod.mockClear(); }); it('点击按钮时会传入指定参数调用myMethod', async () => { const user = userEvent.setup(); render(<MyComponent />); const button = screen.getByText('MyButton'); await user.click(button); // 校验调用次数和传入参数 expect(mockMyMethod).toHaveBeenCalledTimes(1); expect(mockMyMethod).toHaveBeenCalledWith(/* 填入当前场景预期的someValue值 */); }); it('其他业务场景下会传入对应参数调用myMethod', async () => { const user = userEvent.setup(); // 可以根据场景给组件传入不同props、或者设置mock返回值构造不同场景 // 例如需要当前用例中Hook返回特定值,可以用mockReturnValueOnce设置 // mockMyMethod.mockReturnValueOnce(/* 当前场景需要的返回值 */); render(<MyComponent /* 传入不同props触发不同逻辑 */ />); const button = screen.getByText('MyButton'); await user.click(button); // 校验当前场景下的调用参数 expect(mockMyMethod).toHaveBeenCalledWith(/* 填入当前场景对应的预期参数 */); }); });
注意:如果需要在单个用例中模拟Hook抛出错误、返回特定状态等特殊逻辑,直接调用
mockMyMethod对应的mock方法(比如mockImplementationOnce、mockReturnValueOnce)即可,这些临时配置会在beforeEach的mockClear执行时被清空,不会影响其他用例。
内容的提问来源于stack exchange,提问作者cbdeveloper
相关产品推荐
相关产品推荐

