编写自动化智能合约测试

在区块链环境中,一个简单的错误可能会让你损失所有的资金 - 甚至更糟,损失你用户的资金!本指南将帮助你通过编写自动化测试来开发健壮的应用程序,这些测试可以验证你的应用程序是否完全按照你预期的方式运行。

我们将介绍以下主题:

关于测试

测试技术有很多种,从 简单的手动验证到复杂的端到端设置,它们各自都有用处。

然而,说到智能合约开发,实践表明合约 单元测试 异常有价值。这些测试编写简单,运行快速,让你能够自信地添加功能和修复代码中的错误。

智能合约单元测试由多个小型、集中的测试组成,每个测试都检查合约的一小部分是否正确。它们通常可以用构成规范的单个句子来表达,例如“管理员能够暂停合约”、“转移 tokens 会发出事件”或“非管理员不能铸造新的 tokens”。

设置测试环境

你可能想知道我们_如何_运行这些测试,因为智能合约是在区块链内部执行的。使用实际的 Ethereum 网络会非常昂贵,虽然测试网是免费的,但它们也很慢(区块时间为 12 秒或更长)。如果我们打算在每次更改代码时运行数百个测试,我们需要更好的东西。

我们将使用一种叫做_本地区块链_的东西:它是真实区块链的精简版本,与互联网断开连接,在你的机器上运行。这将大大简化事情:你不需要获得 Ether,并且会立即挖掘出新的区块。

编写单元测试

我们将使用 Chai 断言进行单元测试,可以通过安装 Hardhat Toolbox 来使用。

$ npm install --save-dev @nomicfoundation/hardhat-toolbox

我们将把测试文件保存在 test 目录中。最好通过镜像 contracts 目录来构建测试:对于那里的每个 .sol 文件,创建一个相应的测试文件。

是时候编写我们的第一个测试了!这些测试将测试 Box 合约的属性 来自之前的指南:一个简单的合约,允许你 retrieve 所有者之前 store 的值。

在你的项目根目录中创建一个 test 目录。我们将把测试保存为 test/Box.test.js。每个测试 .js 文件通常包含单个合约的测试,并以该合约命名。

// test/Box.test.js
// Load dependencies
const { expect } = require('chai');

// Start test block
describe('Box', function () {
  before(async function () {
    this.Box = await ethers.getContractFactory('Box');
  });

  beforeEach(async function () {
    this.box = await this.Box.deploy();
    await this.box.waitForDeployment();
  });

  // Test case
  it('retrieve returns a value previously stored', async function () {
    // Store a value
    await this.box.store(42);

    // Test if the returned value is the same one
    // Note that we need to use strings to compare the 256 bit integers
    expect((await this.box.retrieve()).toString()).to.equal('42');
  });
});
已经有很多关于如何构建单元测试的书籍。查看 Moloch Testing Guide,了解一套专为测试 Solidity 智能合约而设计的原则。

我们现在准备好运行我们的测试了!

运行 npx hardhat test 将执行 test 目录中的所有测试,检查你的合约是否以你希望的方式工作:

$ npx hardhat test


  Box
    ✓ retrieve returns a value previously stored


  1 passing (578ms)

此时,设置一个持续集成服务(例如 CircleCI)也是一个非常好的主意,以便在每次将代码提交到 GitHub 时自动运行测试。

执行复杂断言

你的合约的许多有趣的属性可能难以捕获,例如:

  • 验证合约是否在错误时恢复

  • 测量帐户的 Ether 余额变化了多少

  • 检查是否发出了正确的事件

我们建议使用 Hardhat Chai Matchers 来帮助你测试所有这些属性,并使用 Hardhat Network Helpers 来模拟区块链上的时间流逝。这些工具将让你编写强大的断言,而无需担心底层 Ethereum 库的底层细节。

下一步

一旦你彻底测试了你的合约并且合理地确定了它们的正确性,你就会想要将它们部署到真实的网上并开始与它们交互。以下指南将让你快速了解这些主题: