7Block Labs
Blockchain Development

ByAUJay

Blockchain Testing Framework and Building Testing Strategy for Blockchain Smart Contracts

Decision‑makers need a test strategy that reduces on‑chain risk without slowing delivery. This guide distills the 2026 state of tooling and prescriptive patterns we implement at 7Block Labs to ship verifiably correct, upgrade‑ready smart contracts across EVM, Solana, Move‑based chains, NEAR, Cosmos SDK, and Fabric.


TL;DR (meta description)

What to use and how to test smart contracts in 2026: a pragmatic, up‑to‑date framework for EVM, Solana, Move, NEAR, Cosmos, and Fabric—covering unit, fuzz, invariants, formal specs, mainnet‑fork tests, coverage, CI/CD, and security gates with precise tool/version guidance.


Why blockchain testing is different now

  • Tooling consolidated: Truffle/Ganache were sunset (archive‑only since Dec 20, 2023), and most EVM teams standardized on Hardhat and Foundry. If your docs or CI still reference Truffle/Ganache, schedule a migration. (archive.trufflesuite.com)
  • Hardhat 3 added first‑class coverage and an expanded helpers API; Foundry v1.0 matured invariants/fork testing and shipped cheatcodes for new protocol features like EIP‑7702 and P‑256 signatures. These are the two fastest paths to comprehensive test coverage on EVM today. (hardhat.org)
  • Security benchmarks evolved beyond the SWC list; maintainers explicitly note the registry hasn’t been actively updated since 2020. Use SWC to label categories, but model your checks and reviewer checklists on SCSVS v2/EthTrust where applicable. (swcregistry.io)

Pick the right stack by chain

EVM (Ethereum and EVM L2s)

  • Foundry suite: forge (tests), anvil (node/fork), cast (CLI). Highlights you should leverage:
    • Fork determinism and speed:
      anvil --fork-url <RPC> --fork-block-number <N>
      with offline start and retry backoff options for flaky RPCs. Pin block numbers in CI to avoid state drift. (getfoundry.sh)
    • Per‑test forking via cheatcodes (
      createFork/selectFork
      ) so complex interactions are isolated and reproducible. (getfoundry.sh)
    • Gas and coverage at your fingertips:
      forge snapshot
      with diff/thresholds and
      forge coverage --report lcov
      for CI artifacts. (learnblockchain.cn)
    • New protocol features: Foundry v1.0 includes EIP‑7702 delegation signing (
      signDelegation/attachDelegation
      ) and P‑256 signing (
      signP256
      ) for ecosystems adopting passkeys. Use
      --hardfork prague
      when validating 7702 flows. (paradigm.xyz)
  • Hardhat 3:
    • Built‑in coverage via
      npx hardhat test --coverage
      , and bundled toolboxes with ethers/viem, matchers, gas reporter. (hardhat.org)
    • Mainnet forking guides recommend pinning a specific block (major stability and 20x cache speedup), powered by archive endpoints. (hardhat.org)
    • Network Helpers (impersonation, storage/nonce/code edits, snapshots) to shape state quickly in tests. (hardhat.org)

Tip: Brownie is no longer actively maintained; if you need Python + pytest semantics, use ApeWorx’s Ape with

ape-test
. (pypi.org)

Solana

  • For Anchor programs, prefer
    anchor test
    against a local validator. For lower‑level Rust programs use
    solana-program-test
    . Consider LiteSVM where you need faster in‑process program tests and clean APIs. (anchor-lang.com)

Move chains (Aptos, Sui)

  • Use the Move Prover (MSL specs) in CI to prove pre/post conditions and invariants; install via
    aptos update prover-dependencies
    . For Sui, use Certora’s Sui Prover or asymptotic-code’s sui-prover where appropriate. (aptos.dev)

NEAR

  • Prefer Workspaces (TS or Rust) to run identical tests on local Sandbox or Testnet, with patch‑state and time travel for deterministic scenarios. Simulation tests (
    near-sdk-sim
    ) exist but docs note it is being deprecated in favor of Workspaces. (near.github.io)

Cosmos SDK / IBC

  • Use the built‑in Simulation framework (SimApp / SimsX) to fuzz transaction sequences and surface state machine failures; complement with interchaintest for E2E and IBC flows. (docs.cosmos.network)

Hyperledger Fabric

  • Exercise chaincode using the Fabric test network and adopt the v2.4+ Peer Gateway client for better throughput vs legacy SDKs. Follow official performance notes on payload sizes and chaincode language trade‑offs (Go > Node > Java). (hyperledger-fabric.readthedocs.io)

A layered test strategy that scales

Design for fast feedback at the bottom and high confidence at the top. For an EVM app, we target:

  1. Unit and property tests
  • Foundry unit tests (pure/internal logic) and Hardhat tests (integration with JS/TS flows).
  • Add runtime assertions with Scribble to turn properties into instrumentation used by fuzzers and SMT tools. (diligence.consensys.io)
  1. Fuzz and invariant tests
  • Foundry fuzzing is built‑in; extend with invariants to explore sequences across handlers and actors. Echidna complements with grammar‑guided campaigns and GitHub Action support. (learnblockchain.cn)
  1. Static and symbolic analysis
  • Slither for fast static checks and architecture insights; Mythril for symbolic execution on bytecode. Wire Slither into code scanning to prevent regressions. (github.com)
  1. Formal proofs for critical paths
  • Solidity: Solidity’s SMTChecker for
    assert
    properties; for higher assurance, use the Certora Prover (CVL rules and invariants). Move chains: Move Prover with MSL specs. (docs.solidity.org)
  1. Mainnet‑fork and protocol integration tests
  • Validate against real deployed dependencies (e.g., oracles, DEX routers) using Anvil/Hardhat forking, pinned to a block. Cache RPC data in CI to avoid provider throttling. (hardhat.org)
  1. Gas/coverage gates
  • Fail PRs when gas regresses beyond tolerance or when coverage dips below agreed floors.
    forge snapshot --check --tolerance
    and
    forge coverage --report lcov
    feed these gates; on Hardhat, enable
    --coverage
    . (learnblockchain.cn)

Practical examples you can drop in

1) Foundry invariant test (EIP‑7702‑aware handler)

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

import {Test} from "forge-std/Test.sol";
import {StdInvariant} from "forge-std/StdInvariant.sol";
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";

contract Treasury {
    address public immutable asset;
    address public guardian;
    mapping(address => bool) public isOperator;

    constructor(address _asset, address _guardian) {
        asset = _asset;
        guardian = _guardian;
    }

    function setOperator(address who, bool on) external {
        require(msg.sender == guardian, "only guardian");
        isOperator[who] = on;
    }

    function drain(address to, uint256 amt) external {
        require(isOperator[msg.sender], "not op");
        IERC20(asset).transfer(to, amt);
    }
}

contract Handler {
    Treasury t;
    IERC20 token;

    constructor(Treasury _t, IERC20 _token) {
        t = _t; token = _token;
    }

    function setOp(address who, bool on) external {
        // simulate guardian txs (EIP-7702: delegate EOAs if needed in future tests)
        t.setOperator(who, on);
    }

    function drain(address to, uint256 amt) external {
        if (token.balanceOf(address(t)) >= amt) {
            t.drain(to, amt);
        }
    }
}

contract Treasury_Invariants is Test, StdInvariant {
    Treasury t;
    IERC20 token;
    Handler h;

    function setUp() public {
        token = IERC20(address(0x...)); // mock or forked addr
        t = new Treasury(address(token), address(this));
        h = new Handler(t, token);
        targetContract(address(h)); // feed fuzzer
    }

    function invariant_TreasuryBalanceNeverNegative() public {
        // Foundry auto-checks invariants after each randomized call
        assertGe(token.balanceOf(address(t)), 0);
    }

    function invariant_OnlyOpsCanDrain() public {
        // Postcondition: any outgoing transfer must be caused by an operator
        // With Scribble you can instrument this as an if_succeeds property too.
        // See: https://diligence.consensys.io/scribble/
    }
}

When testing smart‑account flows (EIP‑7702), enable Prague in

foundry.toml
and use
vm.signDelegation/attachDelegation
in targeted tests to simulate delegated EOAs. (getfoundry.sh)

2) Hardhat mainnet‑fork test with pinned block and impersonation

import { expect } from "chai";
import { ethers, network } from "hardhat";

describe("Router sanity on fork", function () {
  const BLOCK = 21345678; // pin to avoid state drift
  const WHALE = "0x...";  // token holder
  const ROUTER = "0x..."; // on-chain router

  before(async () => {
    await network.provider.request({
      method: "hardhat_reset",
      params: [{ forking: { jsonRpcUrl: process.env.ARCHIVE_RPC!, blockNumber: BLOCK } }],
    });
    const { networkHelpers } = await network.connect();
    await networkHelpers.impersonateAccount(WHALE);
  });

  it("swaps without revert", async () => {
    const whale = await ethers.getSigner(WHALE);
    const router = await ethers.getContractAt("IRouter", ROUTER);
    // ... craft swap tx
    const tx = await router.connect(whale).swapExactTokensForTokens(/* ... */);
    await expect(tx).to.emit(router, "Swap");
  });
});

Hardhat’s forking docs emphasize pinning a block and using an archive node; Helpers expose impersonation, snapshots, and direct storage edits for deterministic tests. (hardhat.org)

3) Scribble property to guard a treasury

/// if_succeeds {:msg "Only operators may drain"} isOperator(msg.sender);
function drain(address to, uint256 amt) external { ... }

Scribble inserts runtime assertions; pair with Echidna and SMTChecker to search counterexamples automatically. (diligence.consensys.io)


Security testing you should automate

  • Slither in PRs (GitHub Action): quick structural issues, upgradeability pitfalls, and architectural diffs; fail on medium+ to keep noise low initially. (github.com)
  • Echidna nightly: property fuzzing with corpus retention; use the official action and limit long‑running tests to nightly or a separate workflow. (github.com)
  • Mythril ad hoc: targeted symbolic runs on critical functions or bytecode of third‑party dependencies. (github.com)
  • Certora Prover (CVL specs): prove invariants like “no loss of total supply,” “only governance may mint,” or “deposit increases underlying balance.” Start with rules templates from docs. (docs.certora.com)
  • Keep SWC as a taxonomy, not a test source of truth; track your controls against SCSVS v2. (github.com)

Coverage and gas as release gates

  • Targets we recommend for DeFi protocols: 90%+ line, 85%+ branch on core contracts; cap max single‑call gas on hot paths with a “red line” budget and fail PRs if
    forge snapshot --check
    diff exceeds tolerance (e.g., 3%). Foundry and Hardhat both output LCOV for CI. (learnblockchain.cn)

CI/CD blueprint (GitHub Actions)

A minimal, fast pipeline that scales to large repos:

name: ci
on: [push, pull_request]

jobs:
  foundry:
    runs-on: ubuntu-latest
    env:
      FOUNDRY_PROFILE: ci
      ETH_RPC_URL: ${{ secrets.ARCHIVE_RPC }}
    steps:
      - uses: actions/checkout@v4
      - uses: foundry-rs/foundry-toolchain@v1
      - run: forge build --sizes
      - run: forge test -vvv
      - run: forge coverage --report lcov
      - run: NO_COLOR=1 forge snapshot --check --tolerance 3 >> $GITHUB_STEP_SUMMARY

Add Slither with official action (fail on medium+), and schedule an Echidna nightly:

  slither:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: crytic/slither-action@v0.4.1
        with:
          fail-on: medium

The Foundry action also caches RPC fork data to reduce provider usage—important when your test matrix expands. (github.com)


Mainnet‑fork testing: pitfalls and fixes

  • Always pin a block and record the RPC provider used; subtle state changes break reproducibility and invalidate gas snapshots. Hardhat/Foundry docs explicitly recommend block pinning. (hardhat.org)
  • Rate limits: enable cache or run a local reth/geth archive for heavy suites; the Foundry action caches RPC responses by default. (github.com)
  • Test sponsorship/passkeys: if your product relies on EIP‑7702 or secp256r1 (RIP‑7212 / EIP‑7951), validate end‑to‑end flows with Foundry cheatcodes and anvil
    --hardfork prague
    . Track cross‑client differences as precompile specs evolve. (paradigm.xyz)

Non‑EVM specifics you should not skip

  • Solana: Prefer
    anchor test
    (spawns a local validator and runs Mocha/TS tests) or
    solana-program-test
    for fine‑grained Rust tests. LiteSVM can substantially shorten cycles for program developers. (anchor-lang.com)
  • Move: Integrate
    aptos move prove
    in PRs; block merges if specified modules lose proofs. For Sui, use Certora Sui Prover or sui‑prover to validate object safety and capability flows. (aptos.dev)
  • NEAR: Workspaces’ spooning and patch‑state features let you import real contract state from mainnet/testnet for deterministic regression tests; the docs note simulation tests are deprecated in favor of Workspaces. (github.com)
  • Cosmos SDK/IBC: Run SimApp/SimsX simulations in Go tests to fuzz chain params and transactions; use interchaintest for IBC paths and relayer behavior. (docs.cosmos.network)
  • Fabric: Exercise chaincode in the Fabric test network, and upgrade client SDKs to use the Peer Gateway for performance; avoid large payloads and long‑running transactions per official guidance. (hyperledger-fabric.readthedocs.io)

Governance, upgrades, and standards

  • Treat SWC as a labeling aid; anchor your checklists on SCSVS v2 and, where relevant, EEA EthTrust guidance referenced by the SWC site itself. This helps align reviewers, auditors, and automated checks. (github.com)
  • For EVM upgradeable contracts, prove “no hidden mint/burn” and “no balance loss” invariants formally (Certora) and at runtime (Scribble), then fuzz sequences around upgrade hooks.

What “good” looks like (our default gates)

  • EVM: forge tests + invariants passing, Hardhat E2E on fork, Slither clean (no high/med), Echidna properties pass N seeds, coverage >=90/85 (line/branch), gas snapshot within 3% tolerance; critical Certora rules green. (github.com)
  • Solana:
    anchor test
    green, program‑test unit/integration, and program size/CU budgets enforced with perf tests.
  • Move: All modules with MSL specs verified by Move Prover; regressions block merges. (aptos.dev)
  • NEAR/Cosmos/Fabric: Representative, deterministic E2E suites with fork/sandbox/simulation artifacts, and performance envelopes captured in CI summaries. (near.github.io)

Final takeaways for decision‑makers

  • Consolidate on Foundry + Hardhat for EVM, Anchor/solana‑program‑test for Solana, Move Prover for Aptos/Sui, NEAR Workspaces, Cosmos SimApp/SimsX, and Fabric test network with Peer Gateway. This reduces team context switching while covering all assurance levels from unit to formal proofs. (hardhat.org)
  • Bake proofs and properties into your SDLC. Don’t ship without invariants and formalized “can’t happen” statements—even a few well‑chosen rules close entire classes of exploits. (docs.certora.com)
  • Make mainnet‑fork tests and gas/coverage gates non‑negotiable. They are cheap insurance, and 80% of production incidents we see would have been caught by the fork suite or a simple property violation.

If you’d like 7Block Labs to map this to your codebase, we typically start with a 2‑week test/assurance uplift: inventory, migrate to modern frameworks, wire CI gates, define 8–12 properties, and land a proving plan on your most critical modules.


Like what you're reading? Let's build together.

Get a free 30‑minute consultation with our engineering team.

Related Posts

7BlockLabs

Full-stack blockchain product studio: DeFi, dApps, audits, integrations.

7Block Labs is a trading name of JAYANTH TECHNOLOGIES LIMITED.

Registered in England and Wales (Company No. 16589283).

Registered Office address: Office 13536, 182-184 High Street North, East Ham, London, E6 2JA.

© 2025 7BlockLabs. All rights reserved.