如何用Jest正确Mock Ethers Provider测试合约调用函数?
正确Mock ethers.providers.Web3Provider 和 ethers.Contract 的 Jest 方案
你的测试问题核心是Mock没有完整覆盖ethers的调用逻辑,尤其是合约方法返回值未模拟成ethers认可的BigNumber类型,同时Web3Provider的初始化链路也需要完整Mock。以下是具体解决步骤:
1. 全局Mock ethers模块
在项目根目录创建__mocks__/ethers.js,全局替换ethers的实现,确保所有依赖都使用模拟逻辑:
const { BigNumber } = require('ethers'); module.exports = { providers: { Web3Provider: jest.fn(() => ({ getSigner: jest.fn(() => ({ getAddress: jest.fn().mockResolvedValue('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266') })) })) }, Contract: jest.fn(() => ({ // 用真实BigNumber实例模拟合约返回值,避免类型错误 cost: jest.fn().mockResolvedValue(BigNumber.from('1000000000000000000')), totalSupply: jest.fn().mockResolvedValue(BigNumber.from('1000')) })), BigNumber: BigNumber };
2. 组件测试文件配置
在组件测试中Mockwindow.ethereum,并验证数据赋值逻辑:
import { mount } from '@vue/test-utils'; import YourComponent from '@/components/YourComponent.vue'; describe('YourComponent', () => { beforeEach(() => { jest.clearAllMocks(); // 模拟window.ethereum基础结构 window.ethereum = { request: jest.fn().mockResolvedValue({}) }; }); it('正确获取合约数据并更新组件状态', async () => { const wrapper = mount(YourComponent); await wrapper.vm.getData(); // 验证组件data是否被正确赋值 expect(wrapper.vm.cost).toBe('1000000000000000000'); expect(wrapper.vm.totalSupply).toBe('1000'); // 验证ethers调用链路是否正确触发 expect(ethers.providers.Web3Provider).toHaveBeenCalledWith(window.ethereum); expect(ethers.Contract).toHaveBeenCalled(); // 可传入合约地址、ABI做精准匹配 expect(wrapper.vm.contract.cost).toHaveBeenCalled(); expect(wrapper.vm.contract.totalSupply).toHaveBeenCalled(); }); });
3. 组件getData函数的关键规范
确保组件内的异步逻辑正确处理Promise和类型转换:
// 组件内的getData示例 async getData() { try { const provider = new ethers.providers.Web3Provider(window.ethereum); const signer = provider.getSigner(); const contract = new ethers.Contract(YOUR_CONTRACT_ADDRESS, YOUR_ABI, signer); const cost = await contract.cost(); const totalSupply = await contract.totalSupply(); this.cost = cost.toString(); this.totalSupply = totalSupply.toString(); } catch (err) { console.error(err); } }
常见错误排查
- 「无效BigNumber值」:必须用
ethers.BigNumber.from()生成模拟返回值,不能直接传字符串/数字,保持和真实合约返回格式一致。 - 组件data未更新:测试时必须用
await等待getData异步执行完成,再做断言。 - 「无法检测网络」:确保Web3Provider的Mock实现包含
getSigner方法,避免ethers内部检测网络时抛出异常。
内容的提问来源于stack exchange,提问作者DamTan
相关产品推荐
相关产品推荐

