Jest问题:仅单测时可重模拟实现,批量运行测试失败
问题根源:单例状态未在测试间重置
你的问题核心在于服务的单例缓存机制和测试间的状态污染:
- 当三个测试一起运行时,前两个测试已经调用过
service.getInstance(),此时服务内部的instance变量被初始化并缓存。后续测试再调用getInstance()时,会直接返回已缓存的实例,完全不会重新执行init()方法——自然也不会触发你在第三个测试里设置的client拒绝mock。 - 而用
it.only单独跑第三个测试时,instance处于初始的未定义状态,init()会正常执行,此时你的mock生效,测试就能通过。
修复方案
1. 在每个测试前重置模块缓存与单例状态
添加beforeEach钩子,让Jest在每个测试前重置模块缓存,确保每次测试都能拿到全新的服务实例,同时重置client的mock状态:
jest.mock('../client'); describe('Service', () => { let service; let client; beforeEach(() => { // 重置模块缓存,重新加载所有相关模块 jest.resetModules(); // 重置client的mock历史与实现 client = require('../client').default; client.mockReset(); // 给client设置默认的成功mock client.mockImplementation(() => Promise.resolve('Mock file')); // 重新导入服务,确保拿到未初始化的单例 service = require('../service').default; }); it('should return a singleton', async () => { const instance1 = await service.getInstance(); const instance2 = await service.getInstance(); expect(instance1).toBe(instance2); }); it('should resolve if the client successfully loads', async () => { expect.assertions(1); await expect(service.getInstance()).resolves.toHaveProperty('makeCall'); }); it('should reject if the client fails to load', async () => { const errorMessage = 'Client could not be initialised.'; expect.assertions(1); // 覆盖默认mock,让client返回拒绝状态 client.mockReturnValueOnce(Promise.reject(new Error(errorMessage))); await expect(service.getInstance()).rejects.toHaveProperty( 'message', errorMessage ); }); });
2. 关键调整说明
jest.resetModules():清空Jest的模块缓存,让每次测试都重新导入service和client,避免单例状态被跨测试缓存。client.mockReset():清除client的mock调用历史和自定义实现,确保每个测试的mock都是干净的初始状态。- 动态导入模块:把原来的顶部静态导入改成
beforeEach里的动态require,配合模块重置实现每次测试的全新环境。
补充:为什么单独跑测试能通过?
当你用it.only执行单个测试时,Jest不会运行前两个测试,service内部的instance变量保持初始的undefined状态。此时调用getInstance()会正常执行init()方法,你的client拒绝mock会被触发,测试自然能通过。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

