如何使用Jest Mock模块内未导出的私有辅助函数?
解决方案
针对ES模块内部未导出私有函数无法直接Mock的问题,有两种常用实现方案:
方案一:轻微调整模块结构(更推荐,无额外依赖)
只需要对原模块做极小改动,将内部依赖的函数挂载到可导出的对象上,即可直接Mock,不影响原有业务逻辑:
- 调整
sumWrapper.js代码
//sumWrapper.js // 把内部私有方法统一挂载到internal对象上 const internal = { sum: (a, b) => { return a + b; } } const sumWrapper = (a, b) => { return internal.sum(a, b); }; // 导出internal对象仅用于测试,业务侧不需要使用 export const _internal = internal; export default sumWrapper;
- 测试代码实现Mock
// sumWrapper.test.js import sumWrapper, { _internal } from './sumWrapper'; test('sumWrapper调用Mock后的乘法sum', () => { // 替换sum方法为Mock实现 const mockSum = jest.spyOn(_internal, 'sum').mockImplementation((a, b) => a * b); expect(sumWrapper(2, 3)).toBe(6); // 测试结束恢复原方法 mockSum.mockRestore(); });
方案二:零侵入修改私有变量(需额外依赖)
如果不方便修改原业务代码,可以用babel-plugin-rewire插件直接修改模块内部私有变量:
- 安装依赖并配置:
执行npm i babel-plugin-rewire -D,然后在babel配置文件的plugins数组中加入"rewire" - 测试代码实现Mock
// sumWrapper.test.js import sumWrapper, { __set__ } from './sumWrapper'; test('sumWrapper调用Mock后的乘法sum', () => { // 直接修改模块内部私有sum变量 __set__('sum', jest.fn((a, b) => a * b)); expect(sumWrapper(2, 3)).toBe(6); });
你的Web3场景适配解法
你提到的Mock web3的getNetwork方法场景其实更简单,不需要修改自己的业务模块,直接Mock第三方web3包的对应方法即可:
假设你的业务代码如下:
// contractAddress.js import Web3 from 'web3'; const web3 = new Web3(window.ethereum); const getAddress = async () => { const network = await web3.eth.net.getNetworkType(); if(network === 'mainnet') return '0x主网合约地址'; if(network === 'goerli') return '0xGoerli测试网合约地址'; return '0x默认地址'; } export default getAddress;
测试代码可以直接Mock整个Web3包的返回:
// contractAddress.test.js import getAddress from './contractAddress'; import Web3 from 'web3'; // 标记web3包为Mock包 jest.mock('web3'); test('Goerli网络下返回对应合约地址', async () => { // 模拟Web3实例返回指定网络 Web3.mockImplementation(() => ({ eth: { net: { getNetworkType: jest.fn().mockResolvedValue('goerli') } } })); const address = await getAddress(); expect(address).toBe('0xGoerli测试网合约地址'); });
内容的提问来源于stack exchange,提问作者AviouslyAK
相关产品推荐
相关产品推荐

