如何使用Hardhat和Chai测试Solidity合约抛出的异常
Solidity合约回退异常测试方案(Hardhat + Chai 技术栈)
问题原因
你之前的写法失效有两个核心原因:
- 普通
to.throw断言仅能捕获同步函数抛出的错误,而合约调用是异步操作,返回的是Promise对象,其抛出的错误无法被同步断言识别 - 若try/catch未生效,大概率是测试用例未正确标记为
async,或未等待合约调用的Promise执行完成就结束了用例
前置配置
首先确保你已经安装了Hardhat官方的Chai匹配器插件,这是处理EVM异常最便捷的工具:
- 安装依赖:
npm install --save-dev @nomicfoundation/hardhat-chai-matchers - 在
hardhat.config.ts中引入插件:
import '@nomicfoundation/hardhat-chai-matchers';
标准测试写法
推荐直接使用匹配器提供的revertedWith断言,代码更简洁易读:
import { expect } from "chai"; import { utils } from "ethers"; describe("Pool contract withdraw logic", () => { it("should revert when withdraw amount exceeds user balance", async () => { // 必须在expect前加await,等待合约调用执行完成 await expect( sut.connect(lp1).withdraw(utils.parseUnits("500000000000")) ).to.be.revertedWith("Pool: not enough balance"); }); })
try/catch兼容写法
如果你偏好使用try/catch手动捕获,可以参考以下正确写法:
it("should revert when withdraw amount exceeds user balance", async () => { let reverted = false; let errorMsg = ""; try { await sut.connect(lp1).withdraw(utils.parseUnits("500000000000")); } catch (e: any) { reverted = true; errorMsg = e.message; } expect(reverted).to.be.true; expect(errorMsg).to.include("Pool: not enough balance"); });
注意事项
revertedWith要求匹配的回退理由和合约中require/revert的字符串完全一致,注意大小写、标点不要写错- 如果你使用的是Solidity自定义错误,可以用
to.be.revertedWithCustomError(contract, "ErrorName")匹配,用法和上面一致 - 所有涉及异步合约调用的断言,必须在
expect前添加await,否则会抛出未捕获的VM异常
内容的提问来源于stack exchange,提问作者Sebastian Celestino
相关产品推荐
相关产品推荐

