区块链分叉测试
区块链测试有四种形式:Unit Test(单元测试),Integration Test(集成测试),Forked Test(分叉测试),Staging Test(阶段测试)。
其中,分叉测试是区块链所独有的测试,它是将所需的链上数据放入本地网络,从而做到以0手续费的方式在模拟现实网络的情况下进行测试。
在这里,我们将以获取 Chainlink Aggregator Version 为例,讲解如何利用 Foundry 实现分叉测试。
测试准备
我们将测试 FundMe.sol
中的这段代码:
function getVersion() public view returns (uint256){
// 获取 Sepolia 测试链上的合约地址
AggregatorV3Interface priceFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306);
return priceFeed.version();
}
测试代码如下:
function testGetVersion() public {
assertEq(fundMe.getVersion(), 4);
}
当 Aggregator 返回的版本为4时,将通过测试。
单元测试报错
如果以单元测试的方式进行测试,我们将得到以下报错:
$ forge test --match-test testGetVersion -vvv
Running 1 test for test/FundMe.t.sol:FundMeTest
[FAIL. Reason: EvmError: Revert] testGetVersion() (gas: 8064)
Traces:
[8064] FundMeTest::testGetVersion()
├─ [2983] FundMe::getVersion() [staticcall]
│ ├─ [0] 0x694AA1769357215DE4FAC081bf1f309aDC325306::version() [staticcall]
│ │ └─ ← ()
│ └─ ← "EvmError: Revert"
└─ ← "EvmError: Revert"
报错内容是:getVersion()
这个函数回滚了。通过经验我们知道,该 Aggregator 只存在于 Sepolia 测试链的相应地址当中,因此当我们去访问本地网络 Anvil 的这个地址时,自然地址为空,函数最终回滚。
分叉测试通过
由于测试函数需要用到真实区块链的信息,因此我们需要将其所需的信息读取到本地网络中,命令和返回结果如下:
$ forge test --match-test testGetVersion -vvvv --fork-url $SEPOLIA_RPC_URL
Running 1 test for test/FundMe.t.sol:FundMeTest
[PASS] testGetVersion() (gas: 14079)
Traces:
[14079] FundMeTest::testGetVersion()
├─ [8815] FundMe::getVersion() [staticcall]
│ ├─ [5753] 0x694AA1769357215DE4FAC081bf1f309aDC325306::version() [staticcall]
│ │ ├─ [398] 0x719E22E3D4b690E5d96cCb40619180B5427F14AE::version() [staticcall]
│ │ │ └─ ← 0x0000000000000000000000000000000000000000000000000000000000000004
│ │ └─ ← 0x0000000000000000000000000000000000000000000000000000000000000004
│ └─ ← 4
└─ ← ()
可以看到返回值确实为4,也就说明成功读取到了 Sepolia 的链上数据。