如何在Hardhat单元测试中访问Solidity合约的public数组字段?
解决Solidity结构体数组在Hardhat测试中的访问问题
错误原因
Solidity中声明为public的数组,自动生成的getter函数必须传入索引参数才能获取对应位置的元素。你直接调用ballot.proposals()不传参数,自然会触发类型不匹配错误——因为函数期望接收一个索引值(BigNumberish类型),但你传了空参数。
解决方法
方法1:逐个访问数组元素(无需修改合约)
在测试中循环遍历每个索引,调用proposals(index)获取对应位置的Proposal结构体,再验证其字段是否符合预期:
describe('Deployment', function () { it('Should set the right proposal names', async function () { const { ballot, names } = await loadFixture(deployFixture); // 循环验证每个提案的名称和初始票数 for (let i = 0; i < names.length; i++) { const proposal = await ballot.proposals(i); expect(proposal.name).to.equal(names[i]); expect(proposal.voteCount).to.equal(0); } }); });
方法2:添加自定义函数批量获取数组(需要修改合约)
如果想一次性获取整个提案数组,可以在Solidity合约中添加一个自定义view函数,直接返回整个proposals数组:
pragma solidity ^0.8.9; contract Ballot { struct Proposal { string name; uint voteCount; } Proposal[] public proposals; constructor(string[] memory proposalNames) { for (uint i = 0; i < proposalNames.length; i++) { proposals.push(Proposal({ name: proposalNames[i], voteCount: 0 })); } } // 新增批量获取提案的函数 function getAllProposals() public view returns (Proposal[] memory) { return proposals; } }
之后在测试中直接调用这个函数,批量验证所有提案:
describe('Deployment', function () { it('Should set the right proposal names', async function () { const { ballot, names } = await loadFixture(deployFixture); const allProposals = await ballot.getAllProposals(); // 遍历验证每个提案的字段 allProposals.forEach((proposal, index) => { expect(proposal.name).to.equal(names[index]); expect(proposal.voteCount).to.equal(0); }); }); });
注:如果数组元素数量极大,批量获取会消耗较多Gas,但单元测试环境下无需顾虑此问题。
内容的提问来源于stack exchange,提问作者Joey Yi Zhao
相关产品推荐
相关产品推荐

