深入解读 Hardhat 测试报告:从测试结果到 Gas 消耗

72 阅读5分钟

当我们在 Hardhat 项目中运行 npx hardhat test 命令时,终端会输出一份详细的报告。这份报告不仅告诉我们测试是否通过,还提供了关于合约编译、Gas 消耗和网络配置的宝贵信息。理解这份报告的每一个部分,对于编写出高效、安全的智能合约至关重要。

image.png 让我们逐段分析一份典型的 Hardhat 测试输出。


第一部分:编译与测试结果摘要

npx hardhat test
Compiled 1 Solidity file successfully (evm target: paris).


  Lock
    Deployment
      ✔ Should set the right unlockTime (58ms)
      ✔ Should set the right owner
      ✔ Should receive and store the funds to lock
      ✔ Should fail if the unlockTime is not in the future
    Withdrawals
      Validations
        ✔ Should revert with the right error if called too soon
        ✔ Should revert with the right error if called from another account
        ✔ Shouldn't fail if the unlockTime has arrived and the owner calls it
      Events
        ✔ Should emit an event on withdrawals
      Transfers
        ✔ Should transfer the funds to the owner


  9 passing (121ms)

这是报告中最直观的部分,也是我们首先会关注的部分。

  • Compiled 1 Solidity file successfully (evm target: paris). 这行告诉我们,Hardhat 成功编译了一个 Solidity 源文件。evm target: paris 指的是编译时所针对的以太坊虚拟机 (EVM) 版本,"Paris" 是以太坊合并 (The Merge) 后的升级代号。这确保了我们的合约字节码与目标链的 EVM 兼容。

  • 测试套件 (Lock) Lock 是我们正在测试的智能合约的名称。接下来的缩进结构清晰地展示了测试用例的组织方式,这通常与我们在测试文件中使用的 describeit 块相对应。

    • Deployment (部署测试): 这个测试块专注于验证合约部署时的初始状态是否正确。

      • ✔ Should set the right unlockTime (58ms): 测试通过,验证了合约部署后 unlockTime 变量被正确设置。括号内的 58ms 表示执行这个测试用例花费的时间。
      • ✔ Should set the right owner: 验证了合约的 owner 是否为部署者。
      • ✔ Should receive and store the funds to lock: 验证了合约在部署时能够正确接收并存储资金。
      • ✔ Should fail if the unlockTime is not in the future: 这是一个重要的负向测试,验证了如果部署时设置的解锁时间是过去的时间点,合约部署应该失败。
    • Withdrawals (提款功能测试): 这个测试块专注于合约的核心功能——提款。它被进一步细分为 Validations (验证)、Events (事件) 和 Transfers (转账)。

      • ✔ Should revert...: 这两个测试验证了在错误条件下(时间未到、调用者非所有者)调用提款函数会如期失败回滚。
      • ✔ Shouldn't fail...: 验证了在正确条件下(时间到达且是所有者调用),提款操作能够成功执行。
      • ✔ Should emit an event on withdrawals: 验证了成功提款时,会触发一个预期的事件(Event)。
      • ✔ Should transfer the funds to the owner: 验证了提款时,合约中的资金确实被转移到了所有者的地址。
  • 9 passing (121ms) 这是最终的测试摘要。它总结了所有测试用例的结果:总共有 9 个测试全部通过,完成所有测试的总耗时为 121 毫秒


第二部分:Gas 和网络配置报告

·············································································································
|  Solidity and Network Configuration                                                                       
························|·················|···············|·················|································
|  Solidity: 0.8.28     ·  Optim: false   ·  Runs: 200    ·  viaIR: false   ·     Block: 30,000,000 gas     
························|·················|···············|·················|································
|  Methods                                                                                                  
························|·················|···············|·················|················|···············
|  Contracts / Methods  ·  Min            ·  Max          ·  Avg            ·  # calls       ·  usd (avg)   │
························|·················|···············|·················|················|···············
|  Lock                 ·                                                                                   
························|·················|···············|·················|················|···············
|      withdraw         ·              -  ·            -  ·         34,096  ·             7  ·           -  
························|·················|···············|·················|················|···············
|  Deployments                            ·                                 ·  % of limit    ·              
························|·················|···············|·················|················|···············
|  Lock                 ·              -  ·            -  ·        326,112  ·         1.1 %  ·           -  
························|·················|···············|·················|················|···············

这部分由 hardhat-gas-reporter 插件生成,提供了关于 Gas 使用情况的详细洞察,这对于优化合约成本至关重要。

  • Solidity and Network Configuration (Solidity 和网络配置)

    • Solidity: 0.8.28: 使用的 Solidity 编译器版本。
    • Optim: false: 表示编译时未开启优化器。在生产环境中,通常会将其设置为 true 以减少 Gas 消耗。
    • Runs: 200: 这是优化器的一个参数,表示假设每个函数被调用的次数。仅在 Optimtrue 时生效。
    • viaIR: false: 表示是否通过中间表示(IR)进行编译,这是一种新的、更强大的优化流程。
    • Block: 30,000,000 gas: 测试时所模拟的区块 Gas 上限 (Block Gas Limit)。
  • Methods (方法) 这张表格分析了在测试过程中,合约的每个外部 (external) 或公共 (public) 函数的 Gas 消耗情况。

    • Contracts / Methods: 合约和方法名。
    • Min / Max / Avg: 在所有调用中,该方法消耗 Gas 的最小值、最大值和平均值。
    • # calls: 在测试中该方法被调用的总次数。
    • usd (avg): 根据预设的 Gas价格 估算出的平均调用成本(美元)。这里显示 - 可能是因为未配置价格或者成本过低。
    • withdraw 函数分析:
      • 平均 Gas 消耗 (Avg) 为 34,096
      • 在测试中总共被调用了 7 次 (# calls)。
  • Deployments (部署) 这张表格展示了部署合约本身所需的 Gas 成本。

    • Lock 合约部署分析:
      • 平均部署成本 (Avg) 为 326,112 Gas
      • % of limit: 部署成本占区块 Gas 上限的百分比,这里是 1.1%。这是一个有用的指标,可以帮助我们判断我们的合约是否过于庞大,以至于有在某些网络上部署失败的风险。

结论

这份 Hardhat 测试报告是一份全面的合约“体检报告”。它告诉我们:

  1. 功能正确性: 所有的 9 个测试用例都已通过,证明 Lock 合约在预设场景下的行为符合预期。
  2. 代码健康度: 测试覆盖了部署、核心功能、边界条件和事件等多个方面,是一套比较完善的测试。
  3. 性能与成本: 我们清晰地看到了 withdraw 函数的平均调用成本和 Lock 合约的部署成本。这些数据是优化的起点。例如,如果部署成本过高,我们可能会考虑将合约拆分或优化存储变量。如果某个函数调用成本异常,我们需要深入代码检查是否存在效率低下的操作。

通过定期运行并仔细分析这份报告,开发者可以持续迭代和改进自己的智能合约,确保其在上线前既安全可靠,又经济高效。