Vue组合式函数测试:Mock内部函数失效问题求助
解决组合式函数内部函数Mock失效问题
问题根源
核心问题是闭包引用导致Mock不生效:onNodeChange内部调用的是useTreeData作用域内直接定义的saveTreeState函数,而非返回对象上的属性引用。你修改treeData.saveTreeState只是替换了返回对象的属性,完全不影响闭包内的函数调用逻辑。
解决方案
方案一:重构组合式(最简洁可靠)
将内部函数挂载到一个共享对象上,让onNodeChange通过该对象调用saveTreeState,这样返回对象的属性和内部引用指向同一个函数:
const useTreeData = () => { // 用对象包裹内部函数,实现共享引用 const methods = { saveTreeState() { // does something } }; function onNodeChange() { // 通过methods对象调用函数 methods.saveTreeState(); } return { ...methods, onNodeChange }; };
测试代码无需修改,替换treeData.saveTreeState即可生效:
const treeData = useTreeData(); treeData.saveTreeState = vi.fn(); treeData.onNodeChange(); expect(treeData.saveTreeState).toHaveBeenCalledOnce();
方案二:Mock整个组合式函数(无需重构原代码)
如果不想改动业务代码,可通过vi.doMock重写桶文件中的useTreeData实现,让它返回带有Mock函数的实例:
// 测试文件顶部 vi.doMock('@/path/to/your-bucket-file', async () => { // 保留桶文件中其他组合式的原实现 const original = await vi.importActual('@/path/to/your-bucket-file'); return { ...original, useTreeData: () => { // 创建Mock的saveTreeState const saveTreeState = vi.fn(); // 重写onNodeChange,使其调用Mock函数 const onNodeChange = () => { saveTreeState(); // 若需保留原onNodeChange的其他逻辑,可调用原函数的对应逻辑 // original.useTreeData().onNodeChange(); }; // 合并原组合式的其他返回属性 const originalReturn = original.useTreeData(); return { ...originalReturn, saveTreeState, onNodeChange }; } }; }); // 测试用例 test('onNodeChange calls saveTreeState', async () => { const { useTreeData } = await import('@/path/to/your-bucket-file'); const treeData = useTreeData(); treeData.onNodeChange(); expect(treeData.saveTreeState).toHaveBeenCalledOnce(); });
方案三:闭包捕获修改内部函数(进阶应急方案)
利用JavaScript闭包特性,借助返回的saveTreeState函数获取内部引用并替换:
test('onNodeChange calls saveTreeState', () => { const treeData = useTreeData(); const spySave = vi.fn(); // 获取闭包内saveTreeState的变量引用 const saveTreeStateRef = Object.getOwnPropertyNames(treeData.saveTreeState)[0]; // 替换闭包内的函数为Mock treeData.saveTreeState[saveTreeStateRef] = spySave; treeData.onNodeChange(); expect(spySave).toHaveBeenCalledOnce(); });
注意:该方法依赖V8引擎的闭包存储实现,兼容性较差,仅作为临时应急方案使用。
内容的提问来源于stack exchange,提问作者EldarGranulo
相关产品推荐
相关产品推荐

