如何在Jest中保留模拟值?遇TypeError问题求解
解决Jest模拟Hook时保留原有模拟值的问题
我编写了全局Hook模拟代码:
jest.mock('hooks/limitIncrease', () => ({ limitIncrease: jest.fn().mockImplementation(() => ({ setReason: jest.fn(), })), }));
在同一文件的某个独立测试用例中,我添加了这段代码来临时修改返回值:
(limitIncrease as jest.Mock).mockReturnValueOnce({ handleSubmitNewLimit: handleSubmitNewLimitMock, });
运行测试时却报错:TypeError: setReason is not a function
我自己有一个解决方案,但觉得不够优雅:
const mockedData = { setReason: jest.fn(), }; jest.mock('hooks/limitIncrease', () => ({ limitIncrease: jest.fn().mockImplementation(() => mockedData), }));
(limitIncrease as jest.Mock).mockReturnValueOnce({ ...mockedData, handleSubmitNewLimit: handleSubmitNewLimitMock, });
错误原因
mockReturnValueOnce会完全替换掉mockImplementation预设的返回对象,新对象里没有setReason方法,导致调用时触发类型错误。
更优解决方案
方案一:复用默认模拟对象
不需要额外维护全局变量,直接从mock的结果中获取默认对象进行扩展:
// 全局Mock保持不变 jest.mock('hooks/limitIncrease', () => ({ limitIncrease: jest.fn().mockImplementation(() => ({ setReason: jest.fn(), })), })); // 测试用例中 (limitIncrease as jest.Mock).mockReturnValueOnce({ ...(limitIncrease as jest.Mock).mock.results[0].value, handleSubmitNewLimit: handleSubmitNewLimitMock, });
通过mock.results[0].value可以拿到mockImplementation返回的默认对象,再合并新属性即可保留原有方法。
方案二:用mockImplementationOnce替换原有实现
利用mockImplementationOnce临时重写实现逻辑,同时复用原实现的返回值:
// 全局Mock保持不变 jest.mock('hooks/limitIncrease', () => ({ limitIncrease: jest.fn().mockImplementation(() => ({ setReason: jest.fn(), })), })); // 测试用例中 (limitIncrease as jest.Mock).mockImplementationOnce(() => ({ ...(limitIncrease as jest.Mock).mockImplementation(), handleSubmitNewLimit: handleSubmitNewLimitMock, }));
这里直接调用原mockImplementation获取默认对象,再添加新方法,逻辑更清晰,也无需额外变量。
方案对比
你原来的方案需要维护一个全局的mockedData变量,上面两种方案都不需要额外维护状态,代码更简洁,也能避免全局变量带来的潜在问题。
内容的提问来源于stack exchange,提问作者Matheus Filype
相关产品推荐
相关产品推荐

