文章介绍了如何通过创建子合约来测试Solidity中的内部函数,并解释为什么不应将函数改为public或virtual。同时还提到了无法测试private函数的原因,并提供了相关代码示例。
要测试一个内部的 Solidity 函数,创建一个继承被测试合约的子合约,用一个外部函数包装父合约的内部函数,然后在子合约中测试这个外部函数。
Foundry 将这一继承合约称为“harness”,而其他人则称之为“fixture”。
不要将函数更改为 virtual 或 public 来方便扩展,你需要测试的是你将实际部署的合约。
以下是一个示例。
contract InternalFunction {
function calculateReward(uint256 depositTime) **internal** view returns (uint256 reward) {
reward = (block.timestamp - depositTime) * REWARD_RATE_PER_SECOND;
}
}
上面的函数为每单位时间的流逝提供了线性奖励率。
fixture(或 harness)看起来像这样:
contract InternalFunctionHarness is InternalFunction {
function calculateReward(uint256 depositTime) **external** view returns (uint256 reward) {
reward = super.calculateReward(depositTime);
}
}
当你调用一个与子合约同名的父合约函数时,必须使用 super 关键字,否则函数会自我调用并进入无限递归。
另外,你可以明确将你的测试函数标记为 harness 或 fixture,如下所示:
contract InternalFunctionHarness is InternalFunction {
function calculateReward_HARNESS(uint256 depositTime) **external** view returns (uint256 reward) {
reward = calculateReward(depositTime);
}
}
将函数更改为 public 不是一个好的解决方案,因为这将增加合约大小。如果一个函数不需要是 public,那就不要将其设为 public。这会增加部署和其他函数执行的 gas 成本。
当一个 合约 接收交易时,它必须将 函数选择器 与所有 public 函数进行线性或二分搜索。无论哪种情况,它都必须搜索更多的选择器。 此外,添加的选择器会增加字节码,从而增加部署成本。
假设我们有以下合约:
contract InternalFunction {
function calculateReward(uint256 depositTime) **internal** view virtual returns (uint256 reward) {
reward = (block.timestamp - depositTime) * REWARD_RATE_PER_SECOND;
}
}
在 fixture 中简单地重写它可能会很诱人以方便使用,但这并不可取,因为这样会导致代码重复,如果你的 harness 实现与父合约不一致,你就不会真正测试你的业务逻辑了。
请注意,这种方法迫使我们复制和粘贴原始代码:
contract InternalFunctionHarness in InternalFunction {
function calculateReward(uint256 depositTime) **external** view override returns (uint256 reward) {
reward = (block.timestamp - depositTime) * REWARD_RATE_PER_SECOND;
}
}
在 Solidity 中没有办法测试私有函数,因为它们在子合约中不可见。内部函数与私有函数之间的区别在合约编译后不存在。因此,你可以将私有函数更改为内部函数,而不会对 gas 成本产生负面影响。
作为读者的练习,基准测试以下代码,看看将 foo
改为内部是否会影响 gas 成本。
contract A {
// 将此更改为私有
function foo() **internal** pure returns (uint256 f) {
f = 2;
}
function bar() **internal** pure returns (uint256 b) {
b = foo();
}
}
contract B is A {
// 146 gas: 0.8.7 no optimizer
function baz() **external** pure returns (uint256 b) {
b = bar();
}
}
请参阅我们的高级 solidity bootcamp 学习更高级的测试方法。
我们还有一个免费的 solidity 教程 帮助你入门。
最初发布于 2023 年 4 月 6 日
- 原文链接: rareskills.io/post/solid...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!