Truffle测试Solidity合约遇仅所有者调用错误,需完善withdrawFunds测试
问题解决:Truffle测试Gaming合约时的权限错误及withdrawFunds测试用例编写
问题分析
执行truffle test时触发以下错误:
Error: Returned error: VM Exception while processing transaction: revert only owner can call this function - - Reason given: Only owner can call this function
核心原因有两点:
- 原Gaming合约未实现withdrawFunds函数:当前Gaming.sol中不存在
withdrawFunds方法,测试用例直接调用会触发异常;且即使实现该函数,也需要权限控制逻辑。 - 测试合约调用权限不足:测试合约
TestGaming并非Gaming合约的owner,调用带isOwner修饰器的函数时会触发revert校验。
修复步骤
1. 补充Gaming合约的withdrawFunds函数
在Gaming.sol中添加带权限控制的资金提取函数,确保只有owner能调用:
function withdrawFunds() external isOwner { uint contractBalance = address(this).balance; require(contractBalance > 0, "No funds to withdraw"); msg.sender.transfer(contractBalance); }
2. 修改测试合约TestGaming.sol
调整测试用例,以Gaming合约owner身份调用withdrawFunds,并验证余额变化:
pragma solidity ^0.5.0; import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../contracts/Gaming.sol"; contract TestGaming { uint public initialBalance = 10 ether; Gaming gaming; address owner; function beforeAll() public { gaming = Gaming(DeployedAddresses.Gaming()); owner = gaming.owner(); // 给合约转入10 ether,确保有可提取资金 (bool success, ) = address(gaming).call.value(10 ether)(""); require(success, "Failed to fund contract"); } function testWithdrawFunds() public { uint ownerBalanceBefore = owner.balance; // 以owner身份调用withdrawFunds (bool success, ) = address(gaming).call(abi.encodeWithSignature("withdrawFunds()")); require(success, "Withdraw failed"); uint ownerBalanceAfter = owner.balance; Assert.equal(10 ether, ownerBalanceAfter - ownerBalanceBefore, "所有者余额应增加10 ether"); } // 保留原有胜负判断测试用例 function testPlayerWonGuessHigher() public { bool expected = true; bool result = gaming.determineWinner(5, 4, true); Assert.equal(expected, result, "玩家猜大应该获胜"); } function testPlayerWonGuessLower() public { bool expected = true; bool result = gaming.determineWinner(5, 6, false); Assert.equal(expected, result, "玩家猜小应该获胜"); } function testPlayerLostGuessLower() public { bool expected = false; bool result = gaming.determineWinner(5, 4, false); Assert.equal(expected, result, "玩家猜小应该失败"); } function testPlayerLostGuessHigher() public { bool expected = false; bool result = gaming.determineWinner(5, 6, true); Assert.equal(expected, result, "玩家猜大应该失败"); } }
3. 关键说明
- 通过
call方法指定调用身份,确保msg.sender为Gaming合约的owner,绕过权限校验。 - 在
beforeAll阶段给合约注入10 ether,保证提取操作有资金可执行。 - 对比提取前后的owner余额,验证资金转移是否符合预期。
测试验证
重新执行truffle test,测试用例将正常通过,不再触发权限错误,且能正确验证owner余额的增长。
内容的提问来源于stack exchange,提问作者Sthio
相关产品推荐
相关产品推荐

