如何在Jest中将模拟函数恢复为原始值?解决静态函数Mock跨测试污染
嘿,这两个问题在Jest测试里挺常见的,我来给你拆解一下解决方案:
根据你创建Mock的方式不同,恢复的方法也不一样,主要分两种场景:
用
jest.spyOn创建的Mock
这是最省心的方式,因为jest.spyOn会自动保留原始函数的引用,测试结束后直接调用mockRestore()就能一键恢复。举个实际例子:// 假设我们有个工具模块utils,里面有fetchData函数 import * as utils from './utils'; test('验证fetchData被Mock后的行为', () => { // 创建Spy并替换为Mock实现 const fetchSpy = jest.spyOn(utils, 'fetchData').mockResolvedValue('模拟返回数据'); // 执行你的测试逻辑... // 恢复原始函数 fetchSpy.mockRestore(); });如果多个测试用例都用到这个Mock,你可以把恢复逻辑放到
afterEach钩子中,避免重复代码:import * as utils from './utils'; let fetchSpy; beforeEach(() => { fetchSpy = jest.spyOn(utils, 'fetchData').mockResolvedValue('模拟返回数据'); }); afterEach(() => { fetchSpy.mockRestore(); }); test('测试场景1', () => { /* ... */ }); test('测试场景2', () => { /* ... */ });手动赋值的Mock(比如直接用
jest.fn()替换)
如果你是直接把函数替换成jest.fn(),那得提前手动保存原始函数的引用,测试结束后再赋值回去:import * as utils from './utils'; // 提前保存原始函数 const originalFetchData = utils.fetchData; test('测试手动Mock的函数', () => { // 替换为Mock函数 utils.fetchData = jest.fn().mockResolvedValue('模拟返回数据'); // 执行测试逻辑... // 恢复原始函数 utils.fetchData = originalFetchData; });
类的静态函数属于类本身的属性,Mock后会全局共享,所以必须确保每个测试用例结束后都清理恢复,这里推荐两种可靠的方法:
优先用
jest.spyOn+mockRestore()
这是最稳妥的方式,spyOn会帮你保留原始静态方法的引用,测试后调用mockRestore()就能恢复原状,完全不会影响其他测试:import User from './User'; test('测试A:Mock User.removeInstance静态方法', () => { // 创建静态方法的Spy并替换为自定义实现 const staticSpy = jest.spyOn(User, 'removeInstance').mockImplementation(() => { console.log('这是Mock的静态方法'); return true; }); // 执行测试A的逻辑... // 恢复原始静态方法 staticSpy.mockRestore(); }); test('测试B:使用原始的User.removeInstance', () => { // 这里调用的已经是类定义的原始方法,不会被测试A的Mock影响 User.removeInstance(); });要是多个测试都需要Mock这个静态方法,同样可以把
spyOn放到beforeEach,mockRestore()放到afterEach,保证每个测试都是独立干净的状态。手动保存原始静态方法再恢复
如果你是直接手动替换静态方法(比如User.removeInstance = jest.fn()),那得提前保存原始方法的引用,测试结束后赋值回去:import User from './User'; // 保存原始静态方法 const originalRemoveInstance = User.removeInstance; test('测试A', () => { User.removeInstance = jest.fn().mockReturnValue(true); // 执行测试逻辑... }); afterEach(() => { // 恢复原始静态方法 User.removeInstance = originalRemoveInstance; }); test('测试B', () => { // 现在调用的就是原始的removeInstance了 User.removeInstance(); });
⚠️ 注意:别把jest.clearAllMocks()或者jest.resetAllMocks()和mockRestore()搞混了!前两个方法只是清除Mock的调用记录、实例和返回值,不会恢复原始函数的实现,只有mockRestore()才会把函数变回最初的样子。
内容的提问来源于stack exchange,提问作者Kourosh

