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

编写依赖数据的函数单元测试时,如何Mock数据?

问题场景
const data = [1,2,3,4]

function parse(index){
  return data[index]
}

假设有一个parse函数,会根据输入的索引从data数组中取值。请问在测试文件中Mock该数据集的最佳方式是什么?

我已了解jest.fn()和spy,但它们似乎更多用于Mock函数。是否有内置方法可以Mock数据集,并让函数指向该Mock数据而非真实数据?我也考虑过重构函数,使其接收data作为输入参数,以便在测试文件中传入Mock数据,但我想了解是否有其他方法。


解决方案

根据你的场景,这里提供几种在Jest中Mock数据集的可行方式,按推荐程度排序:

1. 依赖注入(最推荐,长期最优)

直接重构函数,让data作为可选参数传入,这是代码可测试性的最佳实践,不需要依赖任何Mock工具:

// 重构后的函数
function parse(index, data = [1,2,3,4]){
  return data[index]
}

// 测试用例
test('parse 从 mock 数据中取值', () => {
  const mockData = [10, 20, 30, 40];
  expect(parse(1, mockData)).toBe(20);
});

这种方式让函数的依赖更明确,同时避免了对全局/模块内部变量的依赖,后续维护和扩展都更方便。

2. Mock 模块导出的变量(适用于data已导出的场景)

如果data是作为模块导出的变量(比如在utils.js中导出),可以直接通过Jest修改导出的变量,或者用jest.mock覆盖模块导出:

方式A:直接修改导出变量

// utils.js
export const data = [1,2,3,4];
export function parse(index){
  return data[index];
}

// 测试文件
import { parse, data } from './utils';

test('修改导出的data变量', () => {
  // 替换原数组内容
  data.splice(0, data.length, ...[5,6,7,8]);
  expect(parse(2)).toBe(7);
});

方式B:用jest.mock覆盖模块导出

import { parse } from './utils';

jest.mock('./utils', () => {
  // 保留原函数,只替换data变量
  const originalModule = jest.requireActual('./utils');
  return {
    ...originalModule,
    data: [100, 200, 300]
  };
});

test('使用mock后的模块数据', () => {
  expect(parse(0)).toBe(100);
});

3. 访问并修改模块私有变量(适用于data未导出的场景)

如果data是模块内部的私有变量(未导出),可以通过Object.defineProperty来覆盖模块内的变量:

// utils.js
const data = [1,2,3,4];
export function parse(index){
  return data[index];
}

// 测试文件
import { parse } from './utils';
import * as utilsModule from './utils';

test('mock 模块私有data变量', () => {
  Object.defineProperty(utilsModule, 'data', {
    value: [9, 8, 7],
    writable: true
  });

  expect(parse(1)).toBe(8);
});

注意:这种方式依赖于模块的编译结果,某些打包工具可能会影响变量的可访问性,稳定性不如前两种方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 03:35:44