Hardhat单元测试中如何断言合约返回的多个值?
Solidity多返回值合约的单元测试断言方法
当Solidity合约函数返回多个不同类型的值时,直接使用数组解构失效通常是因为以太坊库(比如ethers.js、web3.js)返回的是特殊的类数组/对象结构,而非普通JS数组。以下是几种可行的解决方式:
1. 直接通过索引访问返回值
不管用什么库,合约调用的返回结果都支持索引访问,这是最稳妥的方式:
// 调用合约函数获取结果 const result = await contractA.getAll(); // 按顺序取出对应返回值 const num = result[0]; const text = result[1]; const flag = result[2]; // 执行断言 expect(num).to.equal(ethers.BigNumber.from(100)); // 注意uint类型是BigNumber expect(text).to.equal("test_data"); expect(flag).to.be.true;
2. 转换为普通数组后解构
如果偏好解构语法,只需把返回的类数组对象转换成普通JS数组即可:
// 用扩展运算符转成普通数组 const [num, text, flag] = [...(await contractA.getAll())]; // 或用Array.from方法 const [num, text, flag] = Array.from(await contractA.getAll()); // 断言逻辑同上 expect(num).to.equal(ethers.BigNumber.from(100));
3. 利用命名返回做对象解构
如果你的Solidity函数是带命名返回的(比如function getAll() returns (uint256 count, string memory content, bool isValid)),可以直接通过属性名解构:
// ethers.js支持直接按命名返回值解构 const { count, content, isValid } = await contractA.getAll(); // Truffle/web3.js则需要从returnValues中解构 const result = await contractA.getAll(); const { count, content, isValid } = result.returnValues; // 断言 expect(count).to.equal(ethers.BigNumber.from(100)); expect(content).to.equal("test_data");
完整测试示例(Hardhat + ethers.js)
describe("ContractA", function () { let contractA; beforeEach(async function () { const ContractA = await ethers.getContractFactory("ContractA"); contractA = await ContractA.deploy(); await contractA.deployed(); }); it("should verify multiple return values correctly", async function () { // 方式1:索引访问 const result = await contractA.getAll(); expect(result[0]).to.equal(ethers.BigNumber.from(5)); expect(result[1]).to.equal("Hello World"); expect(result[2]).to.be.true; // 方式2:数组解构 const [count, message, status] = [...result]; expect(count).to.equal(ethers.BigNumber.from(5)); expect(message).to.equal("Hello World"); expect(status).to.be.true; // 方式3:命名属性解构 const { count: namedCount, message: namedMsg, status: namedStatus } = result; expect(namedCount).to.equal(ethers.BigNumber.from(5)); expect(namedMsg).to.equal("Hello World"); expect(namedStatus).to.be.true; }); });
注意事项
- Solidity的数值类型(如
uint256)在ethers.js中会返回BigNumber类型,断言时要避免用普通数字直接对比,需用ethers.BigNumber.from()转换后再比较。 - Truffle使用web3.js时,返回结果会包含
returnValues对象,可同时通过索引和命名字段访问。
内容的提问来源于stack exchange,提问作者Chamara Ariyarathne
相关产品推荐
相关产品推荐

