我有一份 Solidity 合约,其中包含一个数组字段。
ragma 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
}));
}
}
我正在尝试在安全帽中编写单元测试,但它在访问
proposals
字段时出现编译错误:
describe('Ballot', function () {
async function deployFixture() {
const [owner, otherAccount] = await ethers.getSigners();
const Lock = await ethers.getContractFactory('Ballot');
const names = [v4(), v4(), v4(), v4()];
const ballot = await Lock.deploy(names);
return { ballot, names, owner, otherAccount };
}
describe('Deployment', function () {
it('Should set the right name', async function () {
const { ballot, names } = await loadFixture(deployFixture);
expect(await ballot.proposals()).to.equal(names);
});
调用
ballot.proposals()
有错误:
Argument of type '[]' is not assignable to parameter of type 'ContractMethodArgs<[arg0: BigNumberish], "view">'.
Type '[]' is not assignable to type '[arg0: Typed | BigNumberish, ViewOverrides]'.
Source has 0 element(s) but target requires
它是一个结构数组,如何从单元测试中访问它?我已经测试过它对于字符串字段效果很好。
您的假设部分正确 -
public
属性自动生成一个 getter 函数。但如果是数组,getter 函数接受一个 uint256
参数,其中包含要访问的数组的索引。
expect(await ballot.proposals(0)).to.equal(names[0]);
来自文档页面:
如果你有一个数组类型的
状态变量,那么你只能通过生成的getter函数检索数组的单个元素。这种机制的存在是为了避免返回整个数组时产生高天然气成本。public
如果你想检索整个数组,你需要在合约中创建一个返回整个数组的自定义函数。
function getAllProposals() external view returns (Proposal[] memory) {
return proposals;
}
expect(await ballot.getAllProposals()).to.equal(names);
注意:您的 JS
names
是字符串数组,但 Solidity proposals
是结构/对象数组。确保您比较相同的值(例如,仅过滤结构中不带 voteCount
的名称)。