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

如何用Mock函数测试控制台命令?Jest Mock失效问题求助

测试控制台脚本时Jest Mock不生效的解决方法

你遇到的核心问题是:用execSync('ts-node index.ts')启动了独立的Node.js进程,而Jest的Mock仅作用于当前测试进程,因此新进程中的函数不会被Mock。以下是两种无需依赖外部函数副作用的测试方案:


方案一:重构脚本,导出可测试的核心逻辑

将原有的自执行函数改为可导出的函数,同时保留命令行执行的入口,这样测试时可以直接调用函数验证逻辑,无需启动新进程。

修改后的index.ts

import { fn1, fn2, fnErr } from './src/functions';

// 导出核心执行逻辑,方便测试
export const run = () => {
  try {
    fn1();
    fn2();
  } catch {
    fnErr();
  }
};

// 仅当脚本作为主模块执行时(命令行启动),才调用run函数
if (require.main === module) {
  run();
}

对应的测试代码index.test.ts

import { run } from './index';
import { fn1, fn2, fnErr } from './src/functions';

// Mock functions模块
jest.mock('./src/functions', () => ({
  fn1: jest.fn(),
  fn2: jest.fn(),
  fnErr: jest.fn(),
}));

describe('Script execution logic', () => {
  // 每次测试后清除Mock调用记录
  afterEach(() => {
    jest.clearAllMocks();
  });

  it('正常执行时调用fn1和fn2,不调用fnErr', () => {
    run();

    expect(fn1).toHaveBeenCalledTimes(1);
    expect(fn2).toHaveBeenCalledTimes(1);
    expect(fnErr).not.toHaveBeenCalled();
  });

  it('发生错误时调用fnErr', () => {
    // 让fn1抛出错误,触发catch分支
    (fn1 as jest.Mock).mockImplementation(() => {
      throw new Error('测试错误');
    });

    run();

    expect(fnErr).toHaveBeenCalledTimes(1);
  });
});

这种方案直接验证函数调用行为,完全脱离控制台输出等副作用,是最推荐的测试方式。


方案二:模拟命令行启动场景(无需新进程)

如果必须验证脚本作为CLI命令执行的行为,可以在测试进程中模拟require.main === module的场景,直接加载脚本触发执行,Mock可以正常生效。

测试代码index.test.ts

import { fn1, fn2, fnErr } from './src/functions';

// Mock functions模块
jest.mock('./src/functions', () => ({
  fn1: jest.fn(),
  fn2: jest.fn(),
  fnErr: jest.fn(),
}));

describe('Command line entry', () => {
  afterEach(() => {
    jest.clearAllMocks();
    // 清除模块缓存,避免多次导入导致的重复执行
    delete require.cache[require.resolve('./index')];
  });

  it('作为CLI启动时正确执行逻辑', () => {
    // 保存原有的require.main
    const originalMain = require.main;
    // 模拟当前模块是主模块(命令行启动)
    require.main = module;

    // 加载脚本,触发执行
    require('./index');

    // 恢复原有的require.main
    require.main = originalMain;

    expect(fn1).toHaveBeenCalled();
    expect(fn2).toHaveBeenCalled();
    expect(fnErr).not.toHaveBeenCalled();
  });
});

这种方式无需启动新进程,Mock可以正常作用,同时也不依赖控制台输出的副作用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:17:47