Foundry智能合约测试设计流程

发布于:2025-07-10 ⋅ 阅读:(13) ⋅ 点赞:(0)

Foundry智能合约测试设计流程

通用测试流程

  1. 测试环境搭建

    • 创建测试合约类,继承自Test
    • setUp函数中初始化被测合约和测试账户
    • 准备必要的模拟数据和环境
  2. 测试用例编写

    • 每个测试函数测试一个具体场景
    • 测试函数名应清晰表达测试目的
    • 遵循AAA模式:Arrange(准备)、Act(执行)、Assert(断言)
  3. 测试执行与调试

    • 使用forge test运行测试
    • 针对失败的测试进行调试和修复

四种测试维度详解

1. 单元测试 (Unit Tests)

目的:测试单个合约功能的正确性,隔离外部依赖。

应该测试的方法

  • fund()的基本捐赠功能
  • 各种修饰器(onlyOwner, canWithdraw, canClaim, notPaused
  • pause()/unpause()功能
  • getUserInfo()等查询函数
  • calculateTokens()内部计算逻辑

测试原则

  • 模拟(Mock)外部依赖,如价格预言机
  • 每个函数的正常路径和异常路径都要测试
  • 测试不同的边界条件

命名规则

test{函数名}_{测试场景}() 

例如:testFund_SuccessfulContribution()testFund_RevertWhenPresaleEnded()

2. 集成测试 (Integration Tests)

目的:测试多个合约组件之间的交互。

应该测试的方法

  • TokenPresalePriceConverter的集成
  • withdrawETH()enableClaim()的联动
  • 完整的捐赠、提现、代币计算、领取流程

测试原则

  • 少量或不模拟外部依赖
  • 测试跨合约调用链
  • 测试状态变化的连续性

命名规则

test{流程名}_{测试场景}()

例如:testFundWithdrawClaim_CompleteFlow()

3. 分叉测试 (Forked Tests)

目的:在真实网络的快照上测试合约与实际环境的交互。

应该测试的方法

  • getLatestETHPriceInUSD()与真实Chainlink预言机交互
  • 任何依赖外部合约或服务的功能

测试原则

  • 使用forge test --fork-url <RPC_URL>
  • 测试与实际外部服务的交互
  • 验证在真实环境中的行为

命名规则

testFork{功能名}_{测试场景}()

例如:testForkPriceConversion_AccurateUsdValue()

4. 阶段测试 (Staging Tests)

目的:模拟生产环境,在部署前进行最终验证。

应该测试的方法

  • 完整的用户流程(端到端测试)
  • 极端场景测试
  • 涉及多个用户和时间流逝的复杂场景

测试原则

  • 不模拟任何依赖,使用真实环境
  • 测试真实的用户交互场景
  • 测试合约在不同状态转换下的行为

命名规则

testStage{场景名}_{期望结果}()

例如:testStageFullPresaleCycle_SuccessfulCompletion()

测试优先级

  1. 首先测试核心功能

    • fund()捐赠逻辑
    • 价格转换功能
    • 提现功能
  2. 然后测试安全控制

    • 访问控制(修饰器)
    • 紧急暂停功能
    • 边界条件处理
  3. 最后测试辅助功能

    • 查询功能
    • 特殊场景

测试用例编写原则

  1. 完整性:覆盖所有关键功能和边界情况
  2. 独立性:每个测试应该独立运行,不依赖其他测试
  3. 可读性:测试代码应清晰表达测试目的和预期结果
  4. 稳定性:避免非确定性行为,如依赖特定时间或区块
  5. 效率:测试应该快速运行,避免不必要的操作

示例测试结构

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import {Test, console} from "forge-std/Test.sol";
import {TokenPresale} from "../../src/TokenPresale.sol";
import {PriceConverter} from "../../src/PriceConverter.sol";

contract TokenPresaleTest_Unit is Test {
    TokenPresale tokenPresale;
    address owner = address(0x1);
    address user1 = address(0x2);

    function setUp() public {
        vm.startPrank(owner);
        tokenPresale = new TokenPresale();
        vm.stopPrank();
        
        // 模拟价格预言机返回
        // ...
    }
    
    function testFund_SuccessfulContribution() public {
        // Arrange
        vm.prank(user1);
        uint256 contributionAmount = 1 ether;
        
        // Act
        vm.deal(user1, contributionAmount);
        tokenPresale.fund{value: contributionAmount}();
        
        // Assert
        assertTrue(tokenPresale.hasContributed(user1));
        assertEq(tokenPresale.userUsdContributed(user1), contributionAmount.getLatestETHPriceInUSD());
    }
    
    // 更多测试...
}

按照这个框架,可以有条理地开发四个维度的测试,确保智能合约的功能正确性和安全性。