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; - 若任一用例失败,会显示具体断言信息与失败位置,此时需检查合约逻辑或测试预期值。
测试执行流程示意
预期输出
测试通过时,终端会显示类似以下摘要(具体行数与时间戳因环境而异):
Contract: Counter
✓ 初始计数应为0
✓ 调用increment后计数应为1
✓ 连续调用increment三次后计数应为4
3 passing (62ms)
该输出为确定性结果,由测试代码逻辑直接推出:初始值为0,一次自增后为1,再三次自增后累计为4。若测试失败,则会在对应用例处显示断言错误,并给出实际计数与预期计数的差异。