如何实现Jest Mock复用?react-i18next复用Mock失效排查
问题原因
你遇到的核心问题是Jest对jest.mock的处理机制:Jest会在测试文件的所有代码执行之前,通过静态分析找出所有顶层的jest.mock调用并优先执行。当你把jest.mock包裹在函数MyReusableMockFunction里时,函数调用是在测试代码执行阶段才发生的,此时Jest已经完成了模块的加载和mock初始化,所以这个mock根本不会生效。
可行的复用替代方案
方案1:利用Jest自动Mock目录(推荐)
Jest支持识别项目根目录下的__mocks__文件夹,只要在该目录下创建与目标模块同名的文件,Jest会自动使用这个mock替代原模块(或通过手动调用jest.mock触发)。
- 创建文件
__mocks__/react-i18next.ts(或.js),内容直接写你的mock逻辑:
export const useTranslation = () => ({ t: (str: string, { ns, defaultValue }) => defaultValue, i18n: { changeLanguage: () => new Promise(() => {}), }, }); export const initReactI18next = { type: '3rdParty', init: () => {}, };
- 在需要使用该mock的测试文件中,只需在顶层添加一行:
jest.mock('react-i18next');
Jest会自动加载__mocks__目录下的对应文件作为mock实现。如果你的Jest配置中开启了automock: true,甚至不需要手动调用jest.mock,会自动生效。
方案2:导出Mock工厂函数,在测试文件顶层调用
把mock的工厂函数单独导出,在测试文件的顶层直接传递给jest.mock(保证Jest能静态分析到)。
- 创建复用文件
src/mocks/react-i18next.ts:
export const createReactI18nextMock = () => ({ useTranslation: () => ({ t: (str: string, { ns, defaultValue }) => defaultValue, i18n: { changeLanguage: () => new Promise(() => {}), }, }), initReactI18next: { type: '3rdParty', init: () => {}, }, });
- 在测试文件中导入并使用:
import { createReactI18nextMock } from '../mocks/react-i18next'; // 必须放在测试文件顶层,Jest才能静态处理 jest.mock('react-i18next', createReactI18nextMock); // 后续写测试用例 test('example test', () => { // ... });
方案3:动态Mock(适合需要动态调整的场景)
如果需要在测试过程中动态切换mock实现,可以使用jest.doMock,但需要配合模块缓存重置:
import { jest } from '@jest/globals'; beforeEach(() => { jest.resetModules(); // 重置模块缓存,确保每次测试都加载新的mock jest.doMock('react-i18next', () => ({ useTranslation: () => ({ t: (str: string, { ns, defaultValue }) => defaultValue, i18n: { changeLanguage: () => new Promise(() => {}), }, }), initReactI18next: { type: '3rdParty', init: () => {}, }, })); });
这种方案适合需要根据不同测试用例调整mock逻辑的场景,一般复用推荐前两种方案。
内容的提问来源于stack exchange,提问作者Devd
相关产品推荐
相关产品推荐

