智能合约测试Skill:把"会亏钱的 bug"挡在上线之前
- 它是什么:一个专注于智能合约测试的 AI 技能包(英文名
testing,技能 ID 13686),把 Foundry 的单元测试、模糊测试、fork 测试、不变性测试方法论固化成可被 AI 助手直接调用的"测试专家脑回路"。 - 它纠正什么:直击开发者与大模型最常犯的测试错误——只测 getter、只测快乐路径、写"重言式测试"、不做模糊测试、不做 fork 测试、状态化协议不做不变性测试。
- 它能产出什么:符合 Foundry 规范的测试文件结构、正确的断言选型、
bound输入绑定、主网分叉测试、Handler + 不变性测试骨架,以及一份可勾选的预部署测试清单。 - 谁最需要:正在写 DeFi、金库、AMM、借贷类合约,需要在上线或审计前把测试补齐的 Solidity 开发者与安全工程师。
- 一句话结论:它不是"再写一个测试生成器",而是先告诉你"什么值得测、什么不该测",再给出可运行的 Foundry 代码。
1. 该技能叫什么?如何下载安装 AI 技能提升开发效率?
基本信息
| 项目 | 内容 |
|---|---|
| 技能中文名 | 智能合约测试Skill |
| 技能英文名 | testing |
| 技能ID | 13686 |
| 核心载体 | 基于 Foundry 的测试方法论与代码范式 |
| 主要能力 | 单元测试、模糊测试、fork 测试、不变性测试 |
它解决什么问题
绝大多数智能合约测试失败,不是"没写测试",而是"写错了测试"。技能文档开篇就列出了四类高频错误:
- 测 getter 和简单函数。测试
name()返回名字毫无价值,真正该测的是边缘情况、失败模式和经济不变性——那些一旦出错就会损失金钱的地方。 - 不做模糊测试。
forge test只能找到你已经想到的 bug,模糊测试才能找到你没想到的。合约里有数学运算、有用户输入、有价值转移,就必须模糊测试。 - 不做 fork 测试。调用 Uniswap、Aave、Chainlink 等外部协议的合约,如果在模拟环境里测试,就会把"只在真实链上状态才会出现的集成 bug"完整地隐藏起来。
- 测试反映实现。测试
deposit(100)之后balance[user] == 100,本质是在测试 Solidity 的赋值语句是否有效,这是一句重言式;正确做法是测试属性与不变性,例如"存款再取款后,用户拿回自己的代币"“总存款永远等于合约余额”。
这个技能的价值,就是把上述判断标准变成 AI 助手写测试时的默认前置条件。
一键安装的思路与步骤
AI 技能包的本质,是把某个垂直领域的专家经验(判断标准 + 代码范式 + 检查清单)固化成一份可加载的知识资产。装一次,之后所有会话里助手都会按这套标准工作,你不需要每次重新"教"它。
- 确认安装前提:你使用的 AI 编程助手或智能体平台需要支持"技能 / Skill"加载机制;同时本地建议具备 Foundry 工具链(
forge、cast等),以便把生成的测试直接跑起来。 - 找到技能:在平台的技能市场、技能仓库或插件入口中,通过技能英文名
testing或技能 ID13686检索;具体入口路径、安装命令与导入方式请以官方说明为准。 - 完成安装 / 启用:按平台提供的安装方式加载该技能包,并确认它在当前项目或会话中处于启用状态(部分平台支持按项目维度挂载技能)。
- 验证是否生效:安装后向助手提一个测试策略问题,例如"我有一个金库合约,存款取款都会改变状态,应该测什么?“。如果回答中出现了"不要测 getter”“需要模糊测试与不变性测试”"用 targetContract 加 Handler"等要点,并给出 Foundry 的
.t.sol文件结构,说明技能已正确加载。 - 落地验证:把生成的测试文件放进
test/目录,执行forge test,能编译并运行即代表链路打通。
提示:该技能的安装方式、是否收费、可用平台范围等内容,请以官方说明为准;本文不对未公开的分发渠道与价格做任何推断。
2. 该技能的主要功能和特点
(1)先校准"测什么",再动笔写代码
技能内置了明确的取舍标准:应该测的是损失金钱的边缘情况(零金额转账、全额转出、转给自己、授权覆盖、精确授权额度转账)、访问控制(非所有者调用管理函数必须 revert、所有者可以暂停)、失败模式(存款为零、超额取款、合约暂停期间操作)。不应该测的是 OpenZeppelin 内部实现、Solidity 语言特性、以及与构造函数一一对应的 getter。
(2)完整的 Foundry 单元测试范式
提供可直接复用的文件骨架:test/MyContract.t.sol 结构、继承 forge-std/Test、setUp() 初始化、用 makeAddr("alice") 生成具名地址、用 vm.prank 模拟调用者、用 vm.expectRevert 校验失败、用 vm.expectEmit 校验事件。命名也遵循 test_RevertWhen_XXX 这类可读性约定。
(3)断言选型指南,避免"用错尺子"
技能给出了断言矩阵:assertEq 做相等判断、assertGt / assertGe / assertLt / assertLe 做大小比较、assertApproxEqAbs / assertApproxEqRel 处理有舍入的数学运算(相对误差以 WAD 表示,1e18 = 100%)、vm.expectRevert 支持"任意恢复 / 指定消息 / 自定义错误选择器"三档精度。做除法、算手续费的场景,用错断言方式会直接导致测试假阳性。
(4)模糊测试:用 bound 而不是 vm.assume
这是技能里最实用的细节之一。Foundry 会自动对带参数的测试函数做模糊测试,而 bound() 是"重塑"输入到有效区间,vm.assume() 是"丢弃"不满足条件的输入——大量使用 assume 会显著降低有效测试覆盖率。技能给出了用 bound(amount, 1e6, 1e30) 约束代币金额、用 bound(feeBps, 1, 10_000) 约束费率区间,并断言"费用 + 余数恒等于原始金额"的写法。
(5)fork 测试:用真实链上状态抓集成 bug
技能明确了 fork 测试的适用边界:"总是"用于调用外部协议的合约、处理有怪癖代币(如 USDT、手续费转账代币、重定价代币)的合约、读取预言机价格的合约;"从不"用于没有外部调用的纯逻辑合约。并强调应固定区块高度(如 vm.createSelectFork("mainnet", 19_000_000))以保证测试可重复。
(6)不变性测试:状态化协议的关键一环
对于金库、AMM、借贷这类有多个交互函数、状态随时间变化的协议,单元测试只能覆盖一条路径,不变性测试才能在数千个随机调用序列中验证属性是否始终成立。技能给出了 targetContract(address(handler)) + Handler 模式 + invariant_ 前缀函数的完整写法,并举例了四条经典不变性:ERC-20 总供应量等于所有余额之和、金库总资产等于实际余额、AMM 每次交换后 x*y >= k、用户总能取回存入资产。
(7)预部署测试清单,可直接当验收标准
最后附上一份勾选清单:自定义逻辑全覆盖、零金额/最大 uint/空数组/自我转移、访问控制验证、所有数学运算至少 1000 次模糊测试、每个外部集成都有 fork 测试、状态化协议有不变性测试、事件用 expectEmit 验证、用 forge snapshot 做 gas 快照防退化、用 slither . 做静态分析且无未处理的高/中危发现、最终 forge test -vvv 全绿。
和"普通 AI 直接写测试"强在哪
普通助手往往顺着你的描述直译成断言,产出大量重言式测试;本技能的输出被一套领域判断标准约束——先筛掉无价值测试,再针对边缘情况、失败模式与经济不变性生成代码,并主动提示你补模糊测试、fork 测试与不变性测试。
3. 如何使用该技能?
第一步:明确你要测的合约与风险面
先把合约类型说清楚(代币 / 金库 / AMM / 借贷 / 带外部集成的策略合约),以及它是否转移价值、是否调用外部协议、是否有多个改变状态的交互函数。这三个信息直接决定技能会给你哪几类测试。
第二步:用自然语言提出测试需求
输入示例:
我有一个 ERC4626 金库合约 MyVault,用户通过
deposit(amount, receiver)存入资产、withdraw(assets, receiver, owner)和redeem(shares, receiver, owner)取出,内部有份额价格换算的数学运算,总计约 300 行。请帮我设计测试方案,并给出 Foundry 测试代码骨架。
第三步:获取分层测试方案
输出说明(预期形态):
- 测试优先级清单:先列出必测的边缘情况与失败模式,明确"不要测 getter"。
- 单元测试骨架:给出
setUp()、具名测试函数、vm.prank与vm.expectRevert用法,例如取款超过存款必须 revert。 - 模糊测试骨架:用
bound约束amount与shares到有效区间,断言"存款后立即取款可拿回本金(允许 1 wei 舍入)"。 - 不变性测试骨架:
invariant_TotalAssetsMatchesBalance()断言vault.totalAssets() == token.balanceOf(address(vault)),并配套 Handler 中的deposit/withdraw引导式随机操作。 - 执行建议:告诉你用哪些命令加严测试强度。
第四步:把代码落盘并运行
把生成的 .t.sol 文件放进 test/ 目录,然后按技能给出的命令逐级加压:
# 基础运行(默认模糊测试 256 次运行)
forge test
# 加严模糊测试强度
forge test --fuzz-runs 10000
# 详细输出,定位失败用例
forge test -vvv
也可以把强度写进项目配置,让 CI 自动继承:
# foundry.toml
# [fuzz]
# runs = 1000
#
# [invariant]
# runs = 512
# depth = 50
第五步:补充 fork 测试(如果合约调用外部协议)
输入示例:
我的策略合约需要调用 Uniswap 的 SwapRouter 把 WETH 换成 USDC,请给我一个 fork 主网指定区块的测试。
输出说明:技能会给出使用真实主网地址常量、vm.createSelectFork("mainnet", 19_000_000) 固定区块、vm.deal 给测试地址发放 ETH、构造 ExactInputSingleParams 并断言 amountOut > 0 的完整用例,同时提醒"生产环境中 amountOutMinimum 绝不能设为 0"。执行方式:
forge test --fork-url <你的 RPC 地址> --fork-block-number 19000000
第六步:按清单收尾
对照预部署测试清单逐项确认,例如用 forge snapshot 拍摄 gas 基准防退化、用 slither . 做静态分析、最终 forge test -vvv 全绿后再进入审计或上线流程。
4. 同类型竞品对比分析
| 方案名称 | 定位 | 核心功能 | 安装/使用门槛 | 适用场景 | 优势与不足 |
|---|---|---|---|---|---|
| 智能合约测试Skill(testing) | 测试方法论 + 代码范式的 AI 技能包 | 单元测试结构、断言选型、模糊测试、fork 测试、不变性测试、预部署清单 | 需支持技能加载的 AI 助手环境;需基础 Foundry 认知 | 需要系统性补齐测试覆盖的 Solidity 项目 | 优势:先纠正"测什么"再给代码,覆盖模糊/fork/不变性三层;不足:不替代真实链上执行,最终仍需本地跑 forge test 验证 |
| 通用 AI 助手直写测试 | 通用代码生成 | 根据描述生成测试代码 | 门槛最低,开箱即用 | 小脚本、简单合约的快速补测 | 优势:响应快、无需加载技能;不足:易产出重言式测试、默认不涉及模糊测试与不变性测试、对 fork 场景覆盖薄弱 |
| Hardhat 测试框架(手工编写) | 传统 JS/TS 测试框架 | 基于 ethers 的单元测试、网络模拟、插件生态 | 需自行搭建工程与编写全部用例 | 前后端同栈的团队、需要 JS 生态工具链的项目 | 优势:生态成熟、调试体验好;不足:模糊测试与状态不变性测试能力弱于 Foundry 原生方案,测试设计仍完全依赖人工经验 |
| 静态分析工具(如 Slither、Mythril) | 自动化漏洞扫描 | 模式匹配、符号执行、危险函数识别 | 需单独安装,需理解报告语义 | 上线前安全检查、CI 质量门禁 | 优势:能发现重入、未检查返回值等已知风险模式;不足:不验证业务逻辑正确性,无法替代单元测试、模糊测试与不变性测试 |
选择建议:静态分析工具与本技能不是替代关系,而是互补——技能文档的预部署清单里,本身就要求"用 slither . 做静态分析且无未处理的高/中危发现",再叠加 forge test 全绿,才是完整的质量闭环。
5. 该技能的典型应用场景与实际体验情况
场景一:第一次独立写 DeFi 合约的新手开发者
角色与痛点:刚学会 Solidity 的开发者,能写出转账逻辑,但打开测试文件就不知道从哪下手,最后只写了几个 getter 测试凑覆盖率。
使用方式:把合约贴给助手,问"这个合约应该测什么、不该测什么"。技能会直接给出"应该测的清单"(零金额、全额转出、转给自己、精确授权额度)和"不要测的清单"(name()、symbol()、decimals() 这些 OpenZeppelin 已覆盖的部分),并附上带 vm.prank 与 vm.expectRevert 的可运行骨架。
实际体验:上手难度低,最大收益不是"省了打字时间",而是建立正确的测试价值观——测试的价值在于覆盖会亏钱的路径,而不是把覆盖率数字刷上去。注意点是初次接触 makeAddr、vm.prank 等 cheatcode 时需要花一点时间理解语义。
场景二:集成 Uniswap / Aave / 预言机的策略合约
角色与痛点:合约本身逻辑没问题,但一上主网就在真实协议的边界情况上出问题;本地模拟环境里一切正常,因为模拟实现"太干净了"。
使用方式:直接说明"我的合约调用了 Uniswap SwapRouter 和 Chainlink 价格源,需要 fork 测试",技能会给出固定区块高度的 fork 用例、真实主网地址常量写法,以及"处理有怪癖代币必须做 fork 测试"的提醒。
实际体验:这是技能里最能体现差异化的部分。fork 测试把"集成 bug"从上线后提前到开发期暴露。注意点有两个:一是需要一个可用的 RPC 端点;二是必须固定 --fork-block-number,否则测试不可重复,今天过明天挂。
场景三:金库 / AMM / 借贷等状态化协议
角色与痛点:这类协议有多个交互函数、状态随时间变化,单元测试写得再多,也只是各自验证了一条路径,无法证明"任意操作序列下协议都不会坏"。
使用方式:向技能描述"合约有 deposit / withdraw / harvest 三个状态改变函数",它会引导你写出 targetContract(address(handler)) + Handler 模式的不变性测试,并给出一组可直接套用的不变性命题,比如"总资产恒等于代币实际余额"“份额价格永不为零”“每次交换后 x*y >= k”。
实际体验:不变性测试的思维门槛最高,但恰恰是价值最大的一层。Handler 的写法一开始容易写错(比如忘了在 Handler 里 deal 代币导致序列提前中断),技能给出的 Handler 模板能显著降低试错成本。
场景四:审计前的自查与交接
角色与痛点:团队准备送审,但不确定"测试到底补够了没有",也说不清哪些地方还没覆盖。
使用方式:让助手按预部署测试清单逐项核对当前项目状态,缺哪项补哪项——模糊测试是否跑够 1000 次、每个外部集成是否有 fork 测试、gas 是否用 forge snapshot 建了基准、slither . 是否有未处理的高/中危发现。
实际体验:清单最适合当"交付前的验收单",能把模糊的"应该差不多了"变成可勾选的客观条目。注意点是清单是通用最佳实践,具体项目还需按自身业务补充专属的经济不变性命题。
6. 该技能能为用户带来的价值
把"测试设计"这件最难的事变成有标准答案的事
写测试代码是体力活,决定测什么是脑力活。技能最大的价值是把领域内公认的测试优先级固化下来:先测会亏钱的路径,再测访问控制与失败模式,最后用模糊测试与不变性测试兜住没想到的情况。用户拿到的不只是代码,而是一套可复用的判断标准。
显著降低模糊测试与不变性测试的入门门槛
这两类测试是智能合约安全的分水岭,但因为概念抽象、模板复杂,很多开发者直接跳过。技能提供了 bound vs vm.assume 的取舍原则、Handler 模式骨架、[invariant] 配置参数,把原本需要读大量文档才能上手的部分压缩成一次对话。
避免无效测试带来的隐性浪费
测试 getter、测试 Solidity 赋值是否有效,这些测试不仅浪费编写时间,还会在 CI 里持续消耗运行时长,更危险的是制造"覆盖率很高"的错觉。技能明确划出"不要测试什么"的红线,让测试精力集中到自定义业务逻辑、数学运算、外部集成点、访问控制边界和经济边缘情况上。
把上线前的质量门禁标准化
“所有数学运算模糊测试至少 1000 次运行”“每个外部协议集成都有 fork 测试”“状态化协议有不变性测试”“slither . 无未处理的高/中危发现”“forge test -vvv 全绿”——这些可勾选、可验收的条目,让团队的质量标准从口头共识变成流程规范,长期看能显著降低因测试缺口导致的安全事故与返工成本。
知识沉淀效应
技能文档本身是一份高质量的 Foundry 测试速查手册。即使不依赖 AI 生成代码,开发者把它当作写测试时的对照清单,也能持续获得收益。
7. 常见问题 FAQ
Q1:这个技能怎么安装?装完怎么确认生效?
A:在支持技能机制的 AI 编程助手或智能体平台中,通过技能英文名 testing 或技能 ID 13686 检索并加载即可,具体入口与安装命令以官方说明为准。验证方法:安装后问助手"一个金库合约应该测什么",若回答中出现"不要测 getter"“需要模糊测试与不变性测试”"用 targetContract 加 Handler"等要点并给出 Foundry 文件结构,说明已生效。
Q2:它会替我把测试跑完吗?还是只给建议?
A:它提供的是测试设计判断与可运行的测试代码骨架,实际执行仍需要你在本地用 Foundry 完成,例如 forge test、forge test --fuzz-runs 10000、forge test --fork-url <RPC> --fork-block-number 19000000 等。技能内的清单也要求最终 forge test -vvv 全绿才算通过。
Q3:这个技能适合谁用?完全不懂 Foundry 能用吗?
A:最适合正在编写或审计 Solidity 合约的开发者、安全工程师和 DeFi 团队。完全零基础也能读懂它给出的测试结构与断言说明,但要真正跑通测试,需要先掌握 Foundry 的基础用法(forge 命令、.t.sol 文件、cheatcode 概念),否则会在环境配置上卡住。
Q4:使用该技能收费吗?
A:技能本身的计费方式取决于你所在平台的规则,本文不对价格做任何推断,请以官方说明为准。技能文档中提到的 Foundry、Slither 等工具属于开源生态,其使用成本以各项目官方说明为准。
Q5:和 Hardhat、静态分析工具比,该怎么选?
A:三者定位不同。Hardhat 是成熟的 JS/TS 测试框架,适合前后端同栈、依赖 JS 生态的团队;Slither、Mythril 等静态分析工具负责扫描已知漏洞模式,但不验证业务逻辑是否正确;本技能聚焦 Foundry 生态下的测试设计方法论,强在模糊测试、fork 测试与不变性测试的落地。实践中推荐组合使用——技能文档的预部署清单本身就要求"跑通 forge test"与"slither . 无未处理的高/中危发现"同时满足。