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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 13:45:01