如何在不修改导出结构的前提下测试函数x是否调用函数y?
你遇到的问题核心是:x内部调用的是模块本地的y函数,而非你导出的那个y引用。所以不管是vi.spyOn监听导出的y,还是单独创建mock函数,都影响不到x内部的调用逻辑。
下面给你几个不用大规模修改原代码的可行方案:
方案1:用Vitest模块mock改写导出逻辑
在测试里通过vi.mock提前替换模块导出的y为mock函数,同时让x指向调用这个mocky的逻辑(相当于间接复用原x的行为,但确保它用的是可监控的y):
import { x, y } from './你的模块文件路径' vi.mock('./你的模块文件路径', () => { const actual = vi.importActual('./你的模块文件路径') // 用mock函数包裹原y的实现 const mockY = vi.fn(actual.y) return { ...actual, y: mockY, // 让x调用mock的y,和原逻辑一致 x: () => mockY() } }) it('x 调用了 y', () => { x() expect(y).toBeCalledTimes(1) })
方案2:用ESMock直接修改模块内部变量
如果不想改动测试里的x逻辑,可以用esmock工具直接替换模块内部的y引用,完全不用改原代码:
- 先装依赖:
npm install esmock --save-dev - 测试代码:
import esmock from 'esmock' it('x 调用了 y', async () => { const mockY = vi.fn() // 加载模块时把内部的y替换成mock函数 const { x } = await esmock('./你的模块文件路径', {}, { './你的模块文件路径': { y: mockY } }) x() expect(mockY).toBeCalledTimes(1) })
方案3:极小改动原代码(最省心)
如果能接受对原代码做一行微小修改,让x调用导出的y,那后续测试就简单了:
原代码修改:
export function y(){} // 把原本的y()改成exports.y()(ES模块也可以用import * as self from './当前文件'; self.y()) export function x(){ exports.y() }
测试代码就能正常运行:
import * as t from './你的模块文件路径' it('x 调用了 y', () => { const spy = vi.spyOn(t, 'y') t.x() expect(spy).toBeCalledTimes(1) })
内容的提问来源于stack exchange,提问作者eli chen
相关产品推荐
相关产品推荐

