You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Hardhat测试call函数回滚分支以实现全代码覆盖?

如何触发Solidity中call调用的失败分支以实现100%代码覆盖率?

问题场景

我希望实现100%代码覆盖率,但某函数中的call调用分支无法覆盖,相关Solidity代码如下:

(bool sent, bytes memory data) = _to.call{value: msg.value}("");
require(sent, "Failed to send Ether");

尝试通过修改收款地址余额来触发失败:

await network.provider.send("hardhat_setBalance", [
 "...address...",
 "0x1000"
]);

但未触发require语句,反而报错:sender doesn't have enough funds to send tx。

技术栈:Hardhat、Solidity、ethers.js、chai.js

解决方案

方法1:使用无法接收ETH的合约地址作为收款方

当收款地址是没有receive或payable fallback函数的合约时,发送ETH的call调用会返回false,从而触发require的失败分支。

步骤:

  1. 在测试文件中编写一个无收款能力的测试合约:
contract NonPayableReceiver {
    // 不定义receive或payable fallback函数,无法接收ETH
}
  1. 部署该合约,将其地址作为_to传入目标函数:
const NonPayableReceiver = await ethers.getContractFactory("NonPayableReceiver");
const nonPayableReceiver = await NonPayableReceiver.deploy();
await nonPayableReceiver.deployed();

// 调用目标函数,传入该合约地址作为收款方
await expect(targetContract.sendEther(nonPayableReceiver.address, { value: ethers.utils.parseEther("0.1") }))
  .to.be.revertedWith("Failed to send Ether");

这样call调用会返回false,触发require语句,覆盖失败分支。

方法2:解决「sender余额不足」的报错

你之前的报错是因为发送交易的测试账户余额不足,和收款地址余额无关。可以先给测试账户充值:

// 给测试账户充值ETH
await network.provider.send("hardhat_setBalance", [
  await ethers.provider.getSigner().getAddress(),
  ethers.utils.parseEther("10").toHexString()
]);

注意:这只是解决报错问题,要触发sent=false仍需配合方法1的思路——普通外部账户(EOA)总能接收ETH,call不会返回false。

方法3:模拟gas不足触发失败(进阶)

通过限制调用时的gas量,让call因gas不足返回false:

// 调用时设置极低的gasLimit,导致call执行失败
await expect(targetContract.sendEther(recipientAddress, { 
  value: ethers.utils.parseEther("0.1"),
  gasLimit: 21000 // 低于call执行所需的最小gas
}))
  .to.be.revertedWith("Failed to send Ether");

这种方法需要精确控制gas量,稳定性不如方法1。

内容的提问来源于stack exchange,提问作者MiKa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 08:37:53