React Native Jest测试中如何正确mock npm包方法
Jest 正确Mock React Native第三方npm包方法
核心错误原因
你之前的写法存在两个致命问题,导致mock不生效:
- 两个功能包均为默认导出(export default),你之前的mock写的是命名导出结构,和包实际导出规则不匹配
- 你将
exitApp定义为返回jest.fn()的普通函数,exitApp本身不是mock函数,Jest无法追踪它的调用记录,断言自然无法通过
正确实现代码
1. 声明顶层Mock
在测试文件最顶部声明两个包的mock,严格匹配包的导出结构:
// Mock 应用退出包 jest.mock('react-native-exit-app', () => ({ __esModule: true, default: { exitApp: jest.fn() } })); // Mock 应用重启包 jest.mock('react-native-restart', () => ({ __esModule: true, default: { Restart: jest.fn() } }));
2. 导入依赖并重置Mock状态
在mock声明之后导入依赖,每个用例执行前清空mock调用记录,避免用例间互相干扰:
import RNExitApp from 'react-native-exit-app'; import RNRestart from 'react-native-restart'; // 导入需要测试的业务模块/组件 import AppErrorBoundary from './your-business-file-path'; // 替换为实际业务文件路径 beforeEach(() => { jest.clearAllMocks(); });
3. 编写测试用例
针对不同场景编写断言,注意直接在导入的包实例上取方法做校验:
describe('应用配置校验逻辑', () => { test('配置缺失时触发应用退出', () => { // 模拟配置缺失的前置条件,比如mock配置模块返回configNotThere = true // 如果逻辑封装在组件中就渲染对应组件,封装在函数中就直接调用目标函数 // 执行断言 expect(RNExitApp.exitApp).toHaveBeenCalledTimes(1); expect(RNRestart.Restart).not.toHaveBeenCalled(); }); test('配置命中时触发应用重启', () => { // 模拟配置存在的前置条件,比如mock配置模块返回configFound = true // 执行业务逻辑 // 执行断言 expect(RNRestart.Restart).toHaveBeenCalledTimes(1); expect(RNExitApp.exitApp).not.toHaveBeenCalled(); }); });
特殊场景处理
如果你的业务判断逻辑是写在模块顶层(即import模块时就会直接执行if判断,不是包裹在函数、组件生命周期内),需要用jest.isolateModules隔离模块加载时机,保证配置mock能在业务逻辑执行前生效:
test('顶层逻辑:配置缺失时退出应用', () => { jest.isolateModules(() => { // 先mock配置模块 jest.mock('./app-config', () => ({ configNotThere: true, configFound: false })); // 隔离上下文内加载业务模块,此时拿到的是mock后的配置 require('./your-top-level-logic-file'); // 断言 expect(RNExitApp.exitApp).toHaveBeenCalledTimes(1); }); });
常见踩坑
- 不要写
exitApp: () => jest.fn():这种写法每次调用exitApp才会返回一个新的mock函数,exitApp本身没有被jest代理,无法统计调用次数 - 不要断言未从mock模块导入的零散变量:必须通过导入的包默认实例访问对应方法做断言
- 不要在mock声明前导入业务模块:Jest的mock提升仅对
jest.mock生效,手动导入的业务模块如果在mock前加载,会拿到原始未mock的包,导致mock失效
内容的提问来源于stack exchange,提问作者Mallikarjun Hampannavar
相关产品推荐
相关产品推荐

