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

使用jest.restoreAllMocks与mockFn.mockReset无法恢复未模拟函数

Jest中mockRestore()无法恢复原函数实现的问题

问题描述

我正在学习Jest,尝试理解mockClear()、mockReset()和mockRestore()的用法,在calc.test.js中编写了测试代码。第一个测试通过,但第二个测试中使用add.mockRestore()或jest.restoreAllMocks()后,调用add(1,2)得到undefined而非预期的3,报错Expected:3 Received:undefined。我尝试调整mockRestore()的位置也无效。我认为mockFn.mockRestore()应恢复原实现,而使用mockReset()才会返回undefined,对此感到困惑。另外有一段无需mockRestore()的代码可正常运行,想了解如何在模拟时正确使用mockRestore()。

出错的测试代码

import {add} from "./calc";

jest.mock("./calc", () => {
  return {
    add: jest.fn(),
  };
});

describe("testing calculator functions", () => {
  test("mocking add function and testing", () => {
    add.mockImplementation((a, b) => a * b);
    expect(add(1, 2)).toBe(2);
  });

  test("testing add without mocking", () => {
    add.mockRestore();
    expect(add(1, 2)).toBe(3);
  });
});

正常运行的代码

describe("testing calculator functions", () => {
  test("mocking add function and testing", () => {
    const mockAdd = jest.fn().mockImplementation((a, b) => a * b);
    expect(mockAdd(1, 2)).toBe(2);
  });

  test("testing add without mocking", () => {
    expect(calc.add(1, 2)).toBe(3);
  });
});

问题原因

你用jest.mock()手动创建了完全自定义的mock(直接返回jest.fn()),这种情况下Jest并没有保留原函数的引用,所以mockRestore()无法恢复原实现——它只能恢复那些**被Jest自动模拟(比如用jest.spyOn()创建的mock)**的函数,因为jest.spyOn()会默认保留原函数的备份。

当前的jest.mock()写法是完全替换了add为一个空的jest mock函数,没有保存原函数的任何信息,调用mockRestore()自然没有可用的原实现可以恢复,所以调用add()会返回undefined(空mock函数的默认返回值)。

正确使用mockRestore()的方法

要让mockRestore()生效,你需要用jest.spyOn()来创建mock,它会自动保留原函数的引用,之后可以通过mockRestore()恢复。或者在jest.mock()中手动保留原函数的引用,不过更推荐前者。

方法1:使用jest.spyOn()

import * as calc from "./calc";

describe("testing calculator functions", () => {
  test("mocking add function and testing", () => {
    // 创建spy并替换实现
    const addSpy = jest.spyOn(calc, 'add').mockImplementation((a, b) => a * b);
    expect(calc.add(1, 2)).toBe(2);
  });

  test("testing add without mocking", () => {
    // 恢复原函数
    jest.spyOn(calc, 'add').mockRestore();
    expect(calc.add(1, 2)).toBe(3);
  });
});

更简洁的方式:在每个测试后自动恢复所有mock

import * as calc from "./calc";

describe("testing calculator functions", () => {
  // 每个测试后自动恢复所有mock
  afterEach(() => {
    jest.restoreAllMocks();
  });

  test("mocking add function and testing", () => {
    jest.spyOn(calc, 'add').mockImplementation((a, b) => a * b);
    expect(calc.add(1, 2)).toBe(2);
  });

  test("testing add without mocking", () => {
    expect(calc.add(1, 2)).toBe(3);
  });
});

方法2:在jest.mock()中手动保留原函数

如果你一定要用jest.mock(),可以通过jest.requireActual()获取原模块的内容,保留原函数的引用:

import {add} from "./calc";

jest.mock("./calc", () => {
  // 获取原模块的真实实现
  const originalModule = jest.requireActual("./calc");
  return {
    ...originalModule,
    // 创建一个spy(会保留原函数)
    add: jest.fn(originalModule.add),
  };
});

describe("testing calculator functions", () => {
  test("mocking add function and testing", () => {
    add.mockImplementation((a, b) => a * b);
    expect(add(1, 2)).toBe(2);
  });

  test("testing add without mocking", () => {
    add.mockRestore();
    expect(add(1, 2)).toBe(3);
  });
});

总结

  • mockRestore()仅对由jest.spyOn()创建的mock或手动保留了原函数引用的mock生效,因为它需要原函数的备份才能恢复。
  • 直接用jest.mock()返回空jest.fn()时,没有原函数备份,mockRestore()无法工作,调用后函数依然是空mock,返回undefined。
  • 推荐使用jest.spyOn()搭配afterEach(jest.restoreAllMocks())的方式,更简洁且不易出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:32:20