You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript Node.js项目中Vitest 0.33.0模拟副作用函数失败求助

解决Vitest中同模块函数模拟失效的问题

问题原因

你的代码里parent函数直接调用的是模块内部的child函数,而非导出的child引用。Vitest的spyOn或模块mock都是针对导出对象进行拦截,无法替换模块内部直接调用的函数引用,导致实际的child依然被执行。

解决方法

方法1:修改原代码,让parent调用导出的child

调整dummy.ts,让parent通过模块导出对象调用child,这样Vitest就能拦截到这个引用:

// dummy.ts
// 引入自身模块,获取导出对象
import * as self from './dummy';

export function parent(): string {
  // 调用导出的child,而非本地函数
  return `foo${self.child()}`;
}

export function child(): string {
  console.log('calling actual child');
  return 'bar';
}

之后你的测试代码就能正常工作:

// dummy.test.ts
import * as dummy from './dummy';

describe('parent', () => {
  it('should return foobaz', () => {
    const spy = vi.spyOn(dummy, 'child').mockReturnValueOnce('baz');
    expect(dummy.parent()).toBe('foobaz');
    expect(spy).toHaveBeenCalled();
    // 测试后恢复原函数
    spy.mockRestore();
  });
});

方法2:不修改原代码,通过模块mock重定义parent

如果不能改动业务代码,可以在mock模块时,重新定义parent函数,让它调用mock后的child:

// dummy.test.ts
import * as dummy from './dummy';

vi.mock('./dummy.ts', async () => {
  const actual = await vi.importActual<typeof import('./dummy.ts')>('./dummy.ts');
  // 定义mock的child
  const mockChild = vi.fn(() => 'baz');
  return {
    ...actual,
    child: mockChild,
    // 重写parent,让它调用mock的child
    parent: () => `foo${mockChild()}`
  };
});

describe('parent', () => {
  it('should return foobaz', () => {
    expect(dummy.parent()).toBe('foobaz');
    expect(dummy.child).toHaveBeenCalled();
  });
});

方法3:拆分模块(推荐长期方案)

将child函数拆分到单独的模块中,比如utils.ts,从根源避免同模块函数调用的问题:

// utils.ts
export function child(): string {
  console.log('calling actual child');
  return 'bar';
}

// dummy.ts
import { child } from './utils';

export function parent(): string {
  return `foo${child()}`;
}

测试代码:

// dummy.test.ts
import * as dummy from './dummy';
import * as utils from './utils';

describe('parent', () => {
  it('should return foobaz', () => {
    const spy = vi.spyOn(utils, 'child').mockReturnValueOnce('baz');
    expect(dummy.parent()).toBe('foobaz');
    expect(spy).toHaveBeenCalled();
    spy.mockRestore();
  });
});

内容的提问来源于stack exchange,提问作者Igor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 07:25:54