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

ES模块("type: module")项目中函数Mock的单元测试方案咨询

ES模块TypeScript项目的单元测试替代方案

我有一个在package.json中配置了"type": "module"的ES模块项目,实际用TypeScript开发,需要对模块内的部分函数进行单元测试。尝试用Jest的unstable_mockModule做Mock时,遇到了报错和类型错误的问题,而且手动实现完整Mock的工作量太大,无法接受。以下是几种可行的替代方案:

代码示例

待测试模块toto.js:

export function main() {
    const res = a();
    return res;
}

export function a() {
    return 10;
}

原测试文件test1.test.js的问题:

import { jest } from "@jest/globals";

jest.useFakeTimers();

// 报错
jest.unstable_mockModule("./toto", () => ({
    ...import("./toto"),
    a: jest.fn(() => -2),
}));

// 类型错误:main is not a function
jest.unstable_mockModule("./toto", () => {
    const totoModule = import("./toto");
    return {
        ...totoModule,
        a: jest.fn(() => -2),
    };
});

方案一:转回CommonJS

  • 移除package.json中的"type": "module"字段,或者在tsconfig.json里把"module"配置为"CommonJS",让TypeScript编译输出CommonJS模块。
  • 这样就能用Jest成熟稳定的jest.mock语法来Mock,不用依赖不稳定的unstable_mockModule,示例如下:
// test1.test.js
const { main } = require('./toto');

jest.mock('./toto', () => {
  // 保留原模块的其他导出,只Mocka函数
  const originalModule = jest.requireActual('./toto');
  return {
    ...originalModule,
    a: jest.fn(() => -2)
  };
});

test('main函数使用Mock后的a函数', () => {
  expect(main()).toBe(-2);
});
  • 缺点:如果项目大量依赖ES模块专属特性(比如顶级await、ES模块路径解析),可能需要调整部分代码适配CommonJS。

方案二:改用Vitest作为测试框架

  • Vitest原生支持ES模块,Mock语法和Jest高度兼容,不需要额外复杂配置就能直接Mock模块内函数,而且对TypeScript的支持开箱即用:
// test1.test.ts
import { vi, expect, test } from 'vitest';
import { main } from './toto';

vi.mock('./toto', async () => {
  const originalModule = await import('./toto');
  return {
    ...originalModule,
    a: vi.fn(() => -2)
  };
});

test('main返回Mock后的结果', () => {
  expect(main()).toBe(-2);
});
  • 优点:测试速度比Jest快,ES模块支持完善,TypeScript无需额外配置,Mock逻辑更直观。

方案三:使用Jasmine进行测试

  • Jasmine从4.x版本开始原生支持ES模块,配置好package.json的"type": "module"后,测试文件用ES模块语法,手动替换导出的函数来实现Mock:
// test1.test.js
import { main, a } from './toto';

describe('main函数测试', () => {
  it('使用Mock的a函数返回正确值', () => {
    // 保存原函数,测试后恢复
    const originalA = a;
    // 替换为Mock函数
    globalThis.a = () => -2;
    expect(main()).toBe(-2);
    // 恢复原函数
    globalThis.a = originalA;
  });
});
  • 注意:Jasmine没有Jest那样的自动模块Mock能力,需要手动处理函数替换,适合模块结构简单的小型项目,胜在配置门槛低。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 06:15:17