2. 使用Truffle编写并运行测试

任务说明

本案例目标是在Truffle框架中为智能合约编写自动化测试并运行,验证合约核心功能是否符合预期。你将创建一个可复现的最小Truffle项目,包含一个简单的计数器合约及其JavaScript测试文件,通过Truffle测试运行器执行测试并观察结果。

项目结构与依赖

需要Node.js(≥12)与npm。在空目录中执行以下命令初始化项目并安装Truffle:

mkdir truffle-test-demo && cd truffle-test-demo
npm init -y
npm install --save-dev truffle@5.11.5
npx truffle init

truffle init会生成contracts/、migrations/、test/目录及配置文件。本案例只需修改contracts/与test/下的文件。

合约实现

在contracts/Counter.sol中写入以下计数器合约,包含自增与读取功能:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Counter {
    uint256 private count;

    function increment() public {
        count += 1;
    }

    function getCount() public view returns (uint256) {
        return count;
    }
}

迁移脚本

在migrations/2_deploy_counter.js中写入部署逻辑:

const Counter = artifacts.require("Counter");

module.exports = function (deployer) {
    deployer.deploy(Counter);
};

测试代码

在test/counter_test.js中编写针对合约的测试用例,覆盖初始状态、自增功能及多次自增的累积效果:

const Counter = artifacts.require("Counter");

contract("Counter", (accounts) => {
    let counterInstance;

    before(async () => {
        counterInstance = await Counter.deployed();
    });

    it("初始计数应为0", async () => {
        const count = await counterInstance.getCount();
        assert.equal(count.toString(), "0", "初始计数不是0");
    });

    it("调用increment后计数应为1", async () => {
        await counterInstance.increment({ from: accounts[0] });
        const count = await counterInstance.getCount();
        assert.equal(count.toString(), "1", "自增后计数不是1");
    });

    it("连续调用increment三次后计数应为4", async () => {
        await counterInstance.increment({ from: accounts[0] });
        await counterInstance.increment({ from: accounts[0] });
        await counterInstance.increment({ from: accounts[0] });
        const count = await counterInstance.getCount();
        assert.equal(count.toString(), "4", "三次自增后计数不是4");
    });
});

测试中before钩子获取已部署的合约实例;三个用例按顺序执行,共享同一合约状态,因此第三个用例的预期值基于前两个用例执行后的累计结果(0→1→4)。

运行与验证

在项目根目录执行以下命令启动测试:

npx truffle test

Truffle会先编译合约,再于内置的测试区块链(Ganache)上自动部署迁移脚本中的合约,随后运行test/目录下的测试文件。判定标准:

  • 终端显示Compiling your contracts...且无编译错误;
  • 三个测试用例全部显示为绿色勾选(✓),并输出3 passing;
  • 若任一用例失败,会显示具体断言信息与失败位置,此时需检查合约逻辑或测试预期值。

测试执行流程示意

npx truffle test 命令行入口 编译合约 Solidity → EVM字节码 部署迁移脚本 2_deploy_counter.js 测试 执行 测试用例执行顺序(共享合约状态) 用例1 初始计数 = 0 用例2 increment → 1 用例3 3次increment → 4 合约状态在用例间保持:0 → 1 → 4 判定:3 passing 即通过

预期输出

测试通过时,终端会显示类似以下摘要(具体行数与时间戳因环境而异):

Contract: Counter
    ✓ 初始计数应为0
    ✓ 调用increment后计数应为1
    ✓ 连续调用increment三次后计数应为4

  3 passing (62ms)

该输出为确定性结果,由测试代码逻辑直接推出:初始值为0,一次自增后为1,再三次自增后累计为4。若测试失败,则会在对应用例处显示断言错误,并给出实际计数与预期计数的差异。