- Published on
Foundry自动化测试方法
- Authors

- Name
- 卢翔宇
- @y9840836216317
Foundry自动化测试方法
1. 核心断言方法 (Core Assertions)
这些是你验证逻辑是否正确的“尺子”,大部分来自于 forge-std/Test.sol。
| 方法名 | 用途 |
|---|---|
assertEq(actual, expected) | 最常用。断言两个值绝对相等。有各种版本适应不同类型(uint, address, string等)。 |
assertTrue(condition) | 断言一个条件为真 (true)。 |
assertFalse(condition) | 断言一个条件为假 (false)。 |
assertGt(a, b) / assertLt(a, b) | 断言 a 大于 (>) 或小于 (<) b。 |
assertGe(a, b) / assertLe(a, b) | 断言 a 大于等于 (>=) 或小于等于 (<=) b。 |
assertNotEq(a, b) | 断言两个值不相等,是 assertEq 的反向操作。 |
- 测试结构与流程 (Test Structure & Flow)
这些是组织你测试代码的“骨架”。
| 名称/方法 | 用途 |
|---|---|
setUp() | 特殊函数,在每个 test... 函数运行前都会执行一次,用于准备一个干净的测试环境。 |
test... (前缀) | Foundry 会将所有以 test 开头的函数识别为标准测试用例。测试必须通过。 |
testFail... (前缀) | 与 test... 相反,它标识这个测试用例预期会失败 (revert)。 |
- VM 作弊码 (Cheatcodes) - Foundry 的超级武器
这是 Foundry 最强大的部分,它允许你“欺骗”以太坊虚拟机(EVM),模拟各种复杂场景。通过 vm 变量来调用。
A. 模拟用户与权限 (Pranking)
| 作弊码 | 用途 |
|---|---|
vm.prank(address) | 核心功能。让下一次外部调用伪装成来自指定的 address。msg.sender 会变成这个地址。 |
vm.startPrank(address) | 开始一段“持续伪装”。之后的所有调用都来自该 address,直到 stopPrank。 |
vm.stopPrank() | 结束 startPrank 的伪装状态。 |
vm.deal(address, amount) | 给指定的 address 发送 amount 数量的 ETH,用于测试需要支付 msg.value 的场景。 |
B. 预期失败与事件 (Expecting Reverts & Events)
| 作弊码 | 用途 |
|---|---|
vm.expectRevert() | 极其重要。断言下一次外部调用必须失败 (revert)。用于测试 require 语句和各种错误条件。 |
vm.expectEmit(...) | 断言下一次外部调用会触发一个特定的事件(Event),并可以检查事件的参数。 |
expectRevert 使用示例:
Solidity
function testFail_MintToZeroAddress() {
// 预期下一次调用会因为 "RewardToken__MintToZeroAddress" 错误而失败
vm.expectRevert(RewardToken.RewardToken__MintToZeroAddress.selector);
rewardToken.mint(address(0), 100);
}
C. 操纵区块链状态 (State Manipulation)
| 作弊码 | 用途 |
|---|---|
vm.warp(block.timestamp) | 改变当前的区块时间戳,用于测试与时间相关的逻辑(如锁仓、解冻)。 |
vm.roll(block.number) | 改变当前的区块号。 |
导出到 Google 表格
4. Fuzz 测试 (Fuzz Testing)
这是 Foundry 的另一个强大功能,它会自动生成随机输入来测试你的函数,寻找边缘情况下的漏洞。
如何使用: 只需给你的
test...函数加上参数即可。示例:
Solidity
// Foundry 会用各种随机的 a 和 b 来调用这个函数 function test_Addition(uint256 a, uint256 b) public { uint256 sum = a + b; assertEq(sum, a + b); }vm.assume(condition): 在 Fuzz 测试中,用于约束随机输入的范围。如果条件不满足,Foundry 会放弃这次测试并生成新的随机数。Solidity
function test_something(uint256 amount) { // 假设 amount 必须大于 0 且小于 totalSupply vm.assume(amount > 0 && amount < rewardToken.totalSupply()); // ... 接下来的测试逻辑 ... }
常用组合拳总结
一个典型的 Foundry 测试流程看起来像这样:
setUp函数:用
makeAddr("label")创建测试账户。用
vm.deal(...)给账户发 ETH。用
vm.prank(...)模拟成部署者来部署你的合约。
test...函数 (成功场景):用
vm.prank(...)模拟不同用户(所有者、普通用户)的调用。用
vm.expectEmit(...)检查事件是否正确触发。用
assertEq等断言函数检查最终状态是否正确(如余额、总供应量)。
testFail...或test...+vm.expectRevert(失败场景):模拟恶意用户或错误输入(如转账超过余额、非所有者调用 onlyOwner 函数)。
使用
vm.expectRevert()来确保合约按预期拒绝了这些非法操作。
Fuzz 测试函数:
为函数添加参数,让 Foundry 帮你找茬。
使用
vm.assume(...)过滤掉无意义的测试输入。
掌握以上这些方法,你就可以为你的智能合约构建一套非常坚实和全面的自动化测试了。