
本文讲解如何在 Jest 中正确隔离测试用的 mock 数据,防止因数组原地修改(如 shift())导致后续测试用例读取到已被变更的数据,从而引发不可靠的测试失败。
本文讲解如何在 jest 中正确隔离测试用的 mock 数据,防止因数组原地修改(如 `shift()`)导致后续测试用例读取到已被变更的数据,从而引发不可靠的测试失败。
在 Jest 单元测试中,若多个测试用例共用同一份引用类型 mock 数据(例如数组),且逻辑中对其执行了原地变异操作(如 Array.prototype.shift()、push()、splice() 等),就会造成测试间状态污染——前一个测试修改了该数组,后一个测试拿到的已是“残缺”数据,导致断言失败,就像问题中第二项测试返回 id: 2 而非预期的 id: 1。
根本原因在于:
✅ mockData = [{ id: 1 }, { id: 2 }, { id: 3 }] 是一个对象引用;
❌ data.shift() 直接修改了该数组本身;
❌ 若多个 it 块复用同一 mockData 变量(尤其在 describe 顶层声明),则所有测试共享同一内存地址,状态无法隔离。
正确做法:每个测试独立构造 fresh mock 数据
将 mockData 的创建移入每个 it 块内部,确保每次调用 getData.mockResolvedValue(mockData) 传入的都是全新数组实例:
it('Should return a id 1', async () => {
const mockData = [{ id: 1 }, { id: 2 }, { id: 3 }]; // ✅ 每次新建数组
getData.mockResolvedValue(mockData);
const response = await Helpers.execute();
expect(response.id).toBe(1);
});
it('Should return a id 1 with true flag', async () => {
const mockData = [{ id: 1 }, { id: 2 }, { id: 3 }]; // ✅ 独立副本,互不影响
getData.mockResolvedValue(mockData);
track.mockResolvedValue({});
const response = await Helpers.execute(true);
expect(response.id).toBe(1);
});其他关键修复点
- 修复异步调用:getData() 是 async 函数,必须用 await getData() 获取实际值,否则 data.shift() 会作用于 Promise 对象而非数组,引发运行时错误或逻辑错乱。
- 规范 mock 位置:jest.mock('./operations') 应置于模块顶层(import 后、describe 前),而非 beforeAll 内。Jest 要求 ESM 模块的自动 mock 必须在编译时静态解析,动态调用 jest.mock() 会导致 mock 失效或行为不一致。
- 移除冗余清理:jest.clearAllMocks() 在 afterEach 中已足够;beforeAll 中调用不仅多余,还可能干扰模块初始化流程。
- 导出函数需显式 export:确保 operations.js 中 getData 和 track 使用 export 语法(如 export async function getData() {...}),否则 jest.mock() 无法正确拦截其行为。
最终推荐结构(精简可靠)
// helpers.test.js
import { Helpers } from './helpers';
import { getData, track } from './operations';
jest.mock('./operations'); // ✅ 模块级 mock
describe('Helpers', () => {
afterEach(() => {
jest.clearAllMocks(); // ✅ 重置所有 mock 调用记录与返回值
});
it('Should return a id 1', async () => {
const mockData = [{ id: 1 }, { id: 2 }, { id: 3 }];
getData.mockResolvedValue(mockData);
const response = await Helpers.execute();
expect(response.id).toBe(1);
});
it('Should return a id 1 with true flag', async () => {
const mockData = [{ id: 1 }, { id: 2 }, { id: 3 }];
getData.mockResolvedValue(mockData);
track.mockResolvedValue({});
const response = await Helpers.execute(true);
expect(response.id).toBe(1);
});
});⚠️ 注意:若业务逻辑确实需要复用可变数据(极少见),应改用 structuredClone(mockData) 或 [...mockData] 创建浅拷贝;但更推荐在测试中始终使用不可变数据建模,从根本上杜绝副作用。
遵循以上实践,即可彻底解决 mock 数据跨测试污染问题,保障 Jest 测试的稳定性、可重复性与可维护性。

















