LESSON 03

Solidity 与 Foundry

测试的价值不在覆盖率数字,而在于能否用独立属性证明正常路径、失败路径、边界值和多步组合行为。

约 90 分钟讲解 + 示例 + Lab + 自测本机记录进度
测试思想

先定义系统保证,再写测试

好的测试描述系统在什么条件下必须成立,而不是把实现代码换一种写法再算一遍。

金属砧、笔记和带绿色终端光的工作台,比喻 Foundry 把合约放上砧座反复敲打
Foundry 是砧。合约放上去,用测试去砸。砸不坏的那几条性质,才配写进审计报告。
  • 先写最小合约和明确不变量,再增加功能。
  • 测试正常、失败、边界和组合调用。
  • 固定依赖、编译器、优化和 EVM 配置。
  • 漏洞实验只在本地或明确授权环境执行。

先看安装,再看测试怎么写

下面是 Cyfrin / Patrick Collins 的 Foundry 长课。本页只要求你看完安装与第一个 forge test。其余章节当作工具书,用到再回看。

Foundry Full Course (Cyfrin)从 0:00 看到项目初始化即可。本课后面的交互会把四层测试和最小攻击实验压缩成可以在网页完成的路径。

四层测试解决不同问题

交互图

四层测试各自证明什么

覆盖率只说明代码被跑过。点一层,看它真正该锁定的属性,以及最常见的假测试。

Unit · 明确输入下的行为

有效断言:未授权调用必须 revert;零值存款必须失败;暂停后不能取款。

无效断言:assertEq(vault.preview(x), vault.convert(x)) 这种只是把实现抄一遍。

先掌握这组命令

网页终端

从空目录到第一条测试

网页里先走一遍成功路径。你自己机器上的输出版本号可以不同,结构应一致。

点运行,逐步看到命令和结果。这里不会碰到你的真实钱包。

vm.prank

改变下一次调用的 msg.sender。

vm.expectRevert

断言调用必须以指定方式失败。

deal

为地址设置 ETH 或 Token 测试余额。

bound

约束 fuzz 输入到有效业务范围。

动手实验

Lab:证明一个访问控制错误

创建 Vulnerable.sol,让任意地址都能修改 owner。先写攻击测试证明未授权调用成功,再增加权限检查和回归测试。

function test_AttackerCanTakeOwnership() public {
    vm.prank(attacker);
    vault.setOwner(attacker);
    assertEq(vault.owner(), attacker);
}

function test_RevertWhenCallerIsNotOwner() public {
    vm.prank(attacker);
    vm.expectRevert();
    fixedVault.setOwner(attacker);
}
完成证据

仓库同时保留 vulnerable、fixed、攻击测试和修复后的回归测试。网页测验通过不算完成,本地测试绿了才算。

课中测验 1 / 3

为什么 100% 覆盖率仍不能证明没有漏洞?

课末自测

为什么 100% 测试覆盖率仍然不能证明合约没有漏洞?

信心
下一课合约漏洞体系 →