如何在Jest每个测试用例中重置导入JSON文件的动态mock
问题原因
jest.mock存在自动提升(hoist)特性,所有jest.mock调用会在测试文件初始化阶段优先执行,写在测试用例内部的多个jest.mock会被统一提升到顶部,最终只会保留最后一个的实现,因此只有首个测试用例的mock看起来生效。jest.resetAllMocks()仅用于清除mock函数的调用记录、重置返回值等配置,不会清除Jest的模块缓存,也不会修改已注册的模块mock实现,因此对你的场景无效。- 如果你在测试文件顶部静态导入了业务方法,业务方法依赖的JSON文件已经被模块缓存,后续修改mock也不会更新已经导入的JSON值。
- 你使用
await import动态导入JSON,属于ES模块导入规范,导入结果是模块对象,JSON内容存在于default属性下,mock时需要匹配这个结构。
解决方案
推荐两种实现方式,按需选择即可:
方案1:可变变量mock(写法最简洁)
在测试文件顶层先完成JSON的mock,指向一个可变变量,每个测试用例直接修改这个变量的值即可:
// 测试文件顶部,定义可变的mock变量 let mockItems = [] // 匹配ES模块导入结构,返回default属性 jest.mock('../assets/items.json', () => ({ default: mockItems })) // 可以直接静态导入需要测试的业务方法 import { selectQuery } from '你的业务代码文件路径' it('test A', () => { mockItems = [1,2,3] const expectedItems = selectQuery('...items') expect(expectedItems).toEqual(mockItems) }) it('test B', () => { mockItems = [3,4,5] const expectedItems = selectQuery('...items') expect(expectedItems).toEqual(mockItems) })
方案2:动态导入+清空模块缓存
如果不想使用全局可变变量,可以通过jest.doMock+jest.resetModules实现每个测试用例独立mock:
// 不要在顶部导入业务方法 beforeEach(() => { // 每次测试前清空所有模块缓存,保证每次导入都是最新的mock结果 jest.resetModules() }) it('test A', async () => { const itemsA = [1,2,3] // 用doMock代替mock,不会被提升,仅当前用例生效 jest.doMock('../assets/items.json', () => ({ default: itemsA })) // 动态导入业务方法,此时内部依赖的JSON是当前mock的结果 const { selectQuery } = await import('你的业务代码文件路径') const expectedItems = selectQuery('...items') expect(expectedItems).toEqual(itemsA) }) it('test B', async () => { const itemsB = [3,4,5] jest.doMock('../assets/items.json', () => ({ default: itemsB })) const { selectQuery } = await import('你的业务代码文件路径') const expectedItems = selectQuery('...items') expect(expectedItems).toEqual(itemsB) })
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

