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

如何使用Node.js内置测试Runner模拟默认导出函数?

如何用Node.js原生测试Runner模拟默认导出的函数

核心方案:使用mock.module()拦截模块导出

Node.js测试runner的mock.fn()无法直接替换默认导出的函数(它仅包装函数,不修改模块引用),而mock.method()只适用于对象方法。正确的做法是用mock.module()拦截整个模块,替换默认导出为mock函数。

1. 自定义模块的默认导出模拟

针对你的defaultExport.js,测试代码示例:

import { test, mock } from 'node:test';
import assert from 'node:assert';

test('模拟默认导出的函数', async () => {
  // 拦截目标模块,替换默认导出为mock函数
  const mockedModule = await mock.module('./defaultExport.js', (exports) => {
    exports.default = mock.fn(() => true);
  });

  // 验证mock效果
  assert.equal(mockedModule.default(), true);
  // 验证mock被调用过
  assert.ok(mockedModule.default.mock.calls.length === 1);
});

如果有依赖该默认导出的其他模块(比如你的wrapper函数),必须在mock之后加载依赖模块,确保它使用的是mock版本:

test('模拟被其他模块依赖的默认导出', async () => {
  // 先mock基础模块
  await mock.module('./defaultExport.js', (exports) => {
    exports.default = mock.fn(() => true);
  });

  // 在mock后加载依赖模块
  const { wrapper } = await import('./wrapper.js');
  assert.equal(wrapper(), true);
});

2. 第三方模块的默认导出模拟(如knex)

对于无法修改的第三方模块,同样用mock.module()拦截替换:

import { test, mock } from 'node:test';
import assert from 'node:assert';

test('模拟第三方模块默认导出(如knex)', async () => {
  // 定义mock函数,模拟knex的行为
  const mockedKnex = mock.fn(() => ({
    select: mock.fn(() => Promise.resolve([]))
  }));

  // 拦截knex模块,替换默认导出
  await mock.module('knex', (exports) => {
    exports.default = mockedKnex;
  });

  // 加载使用knex的业务模块
  const { queryData } = await import('./your-knex-usage.js');
  const result = await queryData();
  
  // 验证mock被调用
  assert.ok(mockedKnex.mock.calls.length === 1);
  assert.deepEqual(result, []);
});

为什么原方法失效?

  • mock.fn()仅包装传入的函数,不会修改模块导出的引用关系,调用原导入的函数时还是会执行原始逻辑。
  • mock.method()只能作用于对象的属性方法,默认导出的独立函数不属于任何对象,因此无法使用。

备选方案:调整导出结构(自定义模块适用)

如果不想用mock.module(),可以在自定义模块中同时保留默认导出和命名导出,兼顾简洁性和可测试性:

// defaultExport.js
export default function myFunction() {
  return false;
}

export { myFunction };

测试时通过命名导出进行mock:

import { test, mock } from 'node:test';
import assert from 'node:assert';
import { myFunction } from './defaultExport.js';

test('通过命名导出模拟', () => {
  const mockedFn = mock.fn(() => true);
  // 替换当前模块中的命名导出引用
  globalThis.myFunction = mockedFn;
  assert.equal(mockedFn(), true);
});

注:这种方法仅在当前测试模块有效,依赖默认导出的其他模块不会同步生效,仅适合简单场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 19:03:28