Search

PythonReactSEOPDF
GitHub Skill

foundry-testing

ALWAYS load before writing or modifying Foundry test files (.t.sol). Covers fuzz testing, gas benchmarks, naming conventions, and test patterns.

towns-protocol☆ 65 Repository stars62 Repository forks

Installation

Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.

View source ↗Guides

Skill instructions

Foundry Testing Best Practices

Fuzz Testing Strategy

  1. Fuzz function inputs by default - When a test function has parameters, Foundry automatically fuzzes them
  2. Use bound() over vm.assume - Prefer bound(value, min, max) to constrain inputs; vm.assume discards runs and wastes iterations
  3. Apply Equivalence Class Partitioning - Only fuzz parameters that affect the code path under test. If a parameter doesn't change behavior, use a fixed representative value
  4. Maximize bounds - Use the widest reasonable bounds to maximize coverage
// Good: bound with max range
amount = bound(amount, 1, type(uint96).max);

// Avoid: vm.assume wastes fuzz runs
vm.assume(amount > 0 && amount < type(uint96).max);

Test Organization

  1. Gas benchmarks use _gas suffix - Enables filtering with forge test --mt gas
  2. Pattern: test_foo_gas() calls test_foo(fixed, values) for deterministic gas measurement
  3. Tests can return values for composition and reuse
  4. Group tests by functionality with section headers
function test_stake_gas() public returns (uint256 depositId) {
    depositId = test_stake(address(this), 1 ether, OPERATOR, 0, address(this));
}

function test_stake(
    address depositor,
    uint96 amount,
    address operator,
    uint256 commissionRate,
    address beneficiary
) public givenOperator(operator, commissionRate) returns (uint256 depositId) {
    // Implementation...
}

Modularity

  1. Extract setup as modifiers - e.g., givenOperator(operator, rate), givenSpaceHasPointedToOperator(space, operator)
  2. Decouple unit tests - Avoid complex dependencies; simpler tests are easier to fuzz
  3. Use harness contracts for testing internal functions
contract MyContractHarness is MyContractBase {
    function internalFunction(uint256 x) external pure returns (uint256) {
        return _internalFunction(x);
    }
}

Coverage Requirements

  1. Verify events with vm.expectEmit
  2. Verify reverts with vm.expectRevert
  3. Test storage slots - Verify EIP-7201 namespaced storage constants
  4. Cover critical paths - All state transitions, edge cases, and error conditions
// Event verification
vm.expectEmit(address(contract));
emit SomeEvent(expectedArg1, expectedArg2);
contract.someFunction();

// Revert verification
vm.expectRevert(SomeError.selector);
contract.shouldRevert();

// Storage slot verification (EIP-7201)
function test_storageSlot() public pure {
    bytes32 slot = keccak256(
        abi.encode(uint256(keccak256("namespace.storage")) - 1)
    ) & ~bytes32(uint256(0xff));
    assertEq(slot, MyStorage.STORAGE_SLOT);
}

Naming Convention

Pattern Usage
test_functionName(params) Fuzz test (default when has parameters)
test_functionName_gas() Gas benchmark with fixed inputs
test_functionName_revertIf_Condition Revert condition tests
test_functionName_EdgeCase Specific edge case tests

Gas Benchmarking Workflow

To compare gas usage before/after code changes:

# 1. Stash source changes (keep test changes)
git stash push -m "optimization" -- src/path/to/Changed.sol

# 2. Run baseline snapshot (--mt gas filters to _gas suffix tests)
forge snapshot --mc TestContract --mt gas

# 3. Pop stash to restore changes
git stash pop

# 4. Run diff against baseline
forge snapshot --mc TestContract --mt gas --diff

This workflow:

  • Keeps new _gas test functions while measuring the old implementation
  • Shows gas delta for each test with percentage change
  • Reports overall gas change summary

Reference Examples

Examples

Read the usage examples in the source repository.

View source ↗

Source history

Indexed on
2026-01-20
Index updated
2026-01-26
Branch
main

Index and sync dates describe this directory. View the source repository for code history.

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!