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

Jest.spyOn在同describe多测试用例中上下文共享问题

问题原因及解决方案

问题出在你用jest.spyOn(Group.prototype, 'xxx')创建的间谍函数挂载在共享的原型对象上,所有测试用例会共用这个间谍。第一个测试执行时触发的方法调用记录会被保留,第二个测试运行时,这些旧的调用记录会被新创建的间谍继续统计,导致断言失败。

解决方法有两种:

1. 每个测试结束后手动恢复原型方法

在每个测试用例中,创建间谍后通过mockRestore()方法恢复原方法,彻底清除间谍的影响:

it('should update only perm and name', async () => {
  const spyOnPerm = jest.spyOn(Group.prototype, 'changePermissions');
  const spyOnName = jest.spyOn(Group.prototype, 'changeName');
  const spyOnIsDpt = jest.spyOn(Group.prototype, 'changeIsDepartment');

  try {
    const command = new ChangeGroupPermissionCommand({
      group,
      propsToChange: {
        permissions: [Permission.createFromBitmap('@iam.11111111')],
        name: 'new name' + Math.random(),
      },
    });
    await context.run(author, async () => {
       await handler.execute(command);
       expect(spyOnPerm).toBeCalledTimes(1);
       expect(spyOnName).toBeCalledTimes(1);
       expect(spyOnIsDpt).not.toBeCalled();
    });
  } finally {
    // 恢复原型上的原方法,清除间谍
    spyOnPerm.mockRestore();
    spyOnName.mockRestore();
    spyOnIsDpt.mockRestore();
  }
});

it('should update only department status', async () => {
  const spyOnPermission = jest.spyOn(Group.prototype, 'changePermissions');
  const spyOnName = jest.spyOn(Group.prototype, 'changeName');
  const spyOnIsDpt = jest.spyOn(Group.prototype, 'changeIsDepartment');

  try {
    const command = new ChangeGroupPermissionCommand({
      group,
      propsToChange: {
        isDepartment: true,
      },
    });
    await context.run(author, async () => {
      await handler.execute(command);
      expect(spyOnPermission).not.toBeCalled();
      expect(spyOnName).not.toBeCalled();
      expect(spyOnIsDpt).toBeCalled();
    });
  } finally {
    spyOnPermission.mockRestore();
    spyOnName.mockRestore();
    spyOnIsDpt.mockRestore();
  }
});

2. 全局统一清理间谍

在测试文件顶部添加afterEach钩子,自动处理所有间谍的清理工作:

// 全局钩子:每个测试结束后恢复所有间谍的原方法
afterEach(() => {
  jest.restoreAllMocks();
});

// 若只需重置调用计数(无需恢复原方法),可改用:
// afterEach(() => {
//   jest.clearAllMocks();
// });

it('should update only perm and name', async () => {
  // 原测试代码保持不变
});

it('should update only department status', async () => {
  // 原测试代码保持不变
});

注意:jest.restoreAllMocks()会恢复所有通过jest.spyOn创建的间谍的原方法,适合需要确保原方法行为不受前序测试影响的场景;jest.clearAllMocks()仅清除调用次数和参数记录,不会恢复原方法,适合仅关注调用计数的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 22:25:19