b bianchina.xyz
bianchina.xyz · 话题 · Foundry测试实战教程

Foundry 测试实战教程:在真实项目中落地高覆盖率工程

通过一个真实 ERC20 + 治理合约项目,演示如何用 Foundry 编写单元测试、fuzz 测试与 invariant 测试,并把覆盖率推到 90% 以上。

1105 关注 · 22 2026-05-24T17:46:46.364467+00:00

回答共 1 条

默认排序 ▾
b
bianchina.xyz 主编
Foundry测试实战教程 领域深度内容
优秀回答者
Foundry测试实战教程 - Foundry 测试实战教程:在真实项目中落地高覆盖率工程

项目背景

本教程以一个简化版 ERC20 + 治理投票项目为例,演示 Foundry 测试在真实工程里的落地步骤。项目包含三个合约:Token.sol、Governor.sol、Treasury.sol,业务规则与主流 DAO 项目类似。

选择真实项目作为练习对象,比单纯练习 Toy Demo 收益高得多。如果你在为 Binance 等专业团队准备合约安全岗位面试,能展示一份覆盖率 90% 以上的 Foundry 测试集,是有力加分项。

单元测试的拆解

单元测试粒度要细:

  • Token.transfer:覆盖正常、零金额、超额三类
  • Token.approve:覆盖 0 → N、N → 0、N → M 三类
  • Governor.propose:覆盖权限、状态机、参数校验
  • Treasury.execute:覆盖时序、签名、二次执行

建议在测试合约里使用辅助函数 _setupActor 与 _giveToken,避免重复样板代码。这一思路适配 必安 内部「测试可读性高于一切」的工程要求。

fuzz 测试设计

fuzz 测试关注「参数空间」是否完整覆盖。对 Token.transfer 来说,可以同时模糊化 sender、receiver、amount 三个参数。Foundry 默认会生成 256 次随机调用,可以通过 forge-config.toml 提高到 10000 次。

关键技巧是使用 vm.assume 排除不感兴趣的输入,比如 amount=0 或 receiver=address(0)。这样 fuzz 才会把搜索预算集中在真正有意义的区域。

invariant 测试设计

本项目的全局不变量包括:

  1. 所有账户余额之和恒等于 totalSupply
  2. 已 execute 的提案不可再次 execute
  3. Treasury 余额单调不减或减少都伴随合规提案

声明这些 invariant 后,Foundry 会随机调用合约函数试图打破规则。一旦失败,立即给出可复现序列,调试效率极高。

覆盖率提升技巧

用 forge coverage 生成报告,关注三类指标:line、function、branch。新手往往满足 line 80% 就停止,但 branch 覆盖率才是质量的真正标尺。提升 branch 的核心方法是为每个 require 与 revert 路径写一个独立用例。

配合 Binance合约 风控团队公开的合约安全 checklist,对照逐项补齐缺失场景,覆盖率 95% 以上完全可达。

持续维护

测试不是一次性工作。每次新增功能、修复 bug 都要同步增补测试。建议把测试纳入 CI 强制门槛:覆盖率下降即合并失败。坚持这一规则一年,团队会形成自然的高质量文化。

经过完整训练,你不仅能写出高覆盖率的 Foundry 测试集,更能用同样的思路对待任何工程任务,这才是这套教程最大的价值。

110 赞同
发布于 2026-05-24T06:12:23.469122+00:00 · 更新于 2026-05-24T17:46:46.364467+00:00