如何对React的useContext Hook进行Mock/Spy测试?
问题:测试依赖useContext的辅助函数失败
我正在尝试对两个导出的辅助函数做单元测试,这两个函数都通过useContext调用默认上下文值,但查了很多资料还是没法成功实现。
原函数代码
export const func1 = () => { const { key1, key2 } = useContext(MyContext); return { key1, key2 }; } export const func2 = () => { const { key2 } = useContext(MyContext); // some more complex stuff here }
原测试代码及报错
import React, { useContext } from 'react'; ... it('with mock', () => { jest.mock('react', () => ({ ...jest.requireActual('react'), useContext: (ctx: any) => mockUseContext(ctx) })); useContext.mockImplementation(ctx => ({ someKey: 'someVal' })); // 报错:Property 'mockImplementation' does not exist on type ' (context: Context ) => T expect(func1()).toBe({ someKey: 'someVal' }); }); it('with spyOn', () => { jest.spyOn(React, 'useContext').mockImplementation(() => ({ someKey: 'someVal' })); expect(func1()).toBe({ someKey: 'someVal' }); });
解决方法
1. 修正jest.mock的使用方式
jest.mock必须放在模块作用域(测试文件顶部),不能嵌套在测试用例里。同时要通过类型断言让TypeScript识别这是个mock函数:
import React, { useContext } from 'react'; import { func1, func2 } from './your-file-path'; import { MyContext } from './your-context-path'; // 全局mock React的useContext jest.mock('react', () => ({ ...jest.requireActual('react'), useContext: jest.fn() })); // 类型断言解决TS类型错误 const mockUseContext = useContext as jest.Mock; it('func1 should return context values', () => { // 模拟上下文返回值 mockUseContext.mockReturnValue({ key1: 'test1', key2: 'test2' }); // 注意:对象比较要用toEqual,toBe是比较引用地址,会失败 expect(func1()).toEqual({ key1: 'test1', key2: 'test2' }); });
2. spyOn的正确用法
如果用spyOn,记得测试结束后恢复mock,避免影响其他测试用例:
it('func2 should use context key2', () => { const mockContext = { key2: 'test-key2' }; const spy = jest.spyOn(React, 'useContext').mockReturnValue(mockContext); // 执行func2并根据逻辑添加断言 func2(); // 验证useContext是否传入了正确的上下文对象 expect(spy).toHaveBeenCalledWith(MyContext); // 清除mock,还原原函数 spy.mockRestore(); });
3. 核心注意点
- 对象比较用
toEqual:toBe比较的是对象引用,测试对象内容必须用toEqual。 - TypeScript类型处理:必须把
useContext断言为jest.Mock,否则会出现类型错误。 - mock作用域控制:
jest.mock是模块级别的,会影响整个测试文件;spyOn可以针对单个用例,用完记得恢复。
内容的提问来源于stack exchange,提问作者physicsboy
相关产品推荐
相关产品推荐

