使用Vitest遇ReferenceError:无法在初始化前访问mock
解决Vitest中Redis Mock的"Cannot access before initialization"错误
问题原因
Vitest会自动将所有vi.mock调用提升到文件代码执行的最顶部,哪怕你把vi.mock写在setExMock定义之后,实际运行时mock工厂函数会先执行,此时setExMock还未被初始化,因此抛出ReferenceError。
解决方案
方案1:使用vi.hoisted()同步提升mock函数
通过vi.hoisted()包裹mock函数的定义,让它和vi.mock一起被提升到顶部,确保mock执行时变量已初始化:
// 用vi.hoisted()将setExMock和mock一同提升 const { setExMock } = vi.hoisted(() => ({ setExMock: vi.fn() })) vi.mock('redis', () => { return { createClient: () => { return { connect: vi.fn(), get: vi.fn(), setEx: setExMock, } }, } }) // 测试中直接使用setExMock test('验证setEx调用参数', () => { // 执行触发setEx的业务逻辑 expect(setExMock).toHaveBeenCalledWith('key', 3600, 'value') })
方案2:在mock工厂内部定义并暴露mock函数
把setExMock定义在mock工厂函数内部,同时通过自定义导出暴露给测试代码:
vi.mock('redis', () => { const setExMock = vi.fn() return { createClient: () => ({ connect: vi.fn(), get: vi.fn(), setEx: setExMock, }), // 自定义导出,供测试用例引用 __setExMock: setExMock } }) // 测试中导入自定义导出的mock函数 import { __setExMock as setExMock } from 'redis' test('验证setEx调用参数', () => { // 执行业务逻辑 expect(setExMock).toHaveBeenCalledWith('key', 3600, 'value') })
说明
两种方案都能解决变量初始化顺序的问题,方案1更贴合你原本的代码结构,无需额外导入;方案2则通过内部定义避免提升问题,适合更复杂的mock场景。
内容的提问来源于stack exchange,提问作者Rodrigo
相关产品推荐
相关产品推荐

