7Block Labs
Blockchain Development

ByAUJay

Blockchain Testing Frameworks Compared: Hardhat, Foundry, and More

Short description: A 2025 field guide to choosing, combining, and hardening modern EVM testing stacks—Hardhat 3 vs. Foundry 1.x—with concrete patterns, code, and CI controls that decision‑makers can adopt today.

Why this guide, now

Over the past 18 months, Ethereum developer tooling has shifted meaningfully: ConsenSys sunset Truffle and Ganache (archived Dec 20, 2023), pushing teams toward Hardhat and Foundry; Hardhat 3 introduced built‑in coverage and a Viem-first toolbox; and Foundry shipped 1.x with faster invariant/fuzz testing and richer cheatcodes. Meanwhile, Python-first stacks consolidated around Ape as Brownie entered low‑maintenance mode. If you’re deciding how to test critical smart contracts in 2025, the delta is big enough that a recalibration pays off. (consensys.io)


Executive summary for decision‑makers

  • If your org is TypeScript-heavy, needs a mature plugin ecosystem, and values flexible deployment orchestration, default to Hardhat 3 with the Viem toolbox and Ignition. Add gas and coverage gates in CI. (hardhat.org)
  • If your team optimizes for raw test speed, deep fuzz/invariant campaigns, and Solidity‑first ergonomics, adopt Foundry for unit/fuzz/invariant testing and local forks; layer on static/dynamic analyzers. (getfoundry.sh)
  • Most high‑assurance teams run a hybrid: Foundry for speed‑critical tests and invariants, Hardhat for TypeScript/infra integration (plugins, verifications, scripted deploys), and Tenderly/Anvil forks for end‑to‑end checks. (github.com)

What changed since 2023

  • Truffle and Ganache were sunset by ConsenSys; archives remain, but no updates beyond late‑2023. Many projects migrated toward Hardhat/Foundry. (consensys.io)
  • Hardhat 3 shipped native code coverage, declarative config, typed artifacts, and new toolbox options (Viem or Ethers). Ignition remains the official declarative deployment path. (hardhat.org)
  • Foundry 1.x improved compilation and invariant test performance; the toolchain (forge/anvil/cast/chisel) continues to emphasize speed and Solidity‑first tests. (paradigm.xyz)
  • Python ecosystem: Brownie explicitly notes it’s no longer actively maintained; Ape Framework is the recommended Python alternative. (pypi.org)

Hardhat 3, concretely (2025 state)

Hardhat is a JavaScript/TypeScript development environment with a batteries‑included plugin model. The 2025 shape:

  • Test coverage built in. Run combined Solidity + TypeScript coverage with a single flag (no third‑party plugin required). (hardhat.org)
  • Viem‑based toolbox for new TS projects (or an Ethers.js toolbox if that fits better). Viem toolbox bundles assertions, network helpers, verification, and Ignition deploys. (hardhat.org)
  • Ignition: declarative deployments with resumable journals, per‑network fee limits, and parallelizable steps. (v2.hardhat.org)
  • Hardhat Network: mainnet forking, account impersonation, time/block manipulation, and state mutators like setBalance/setStorageAt—plus helpers to call them ergonomically in tests. (v2.hardhat.org)
  • Solidity console.log for in‑Solidity debugging on the local simulator. (hardhat.org)
  • Gas analysis via the widely used gas‑reporter plugin (recently updated for Etherscan API v2), still valuable even with built‑in coverage. (npmjs.com)

Example: Enable coverage for Solidity and TS tests

# Run all tests with coverage
npx hardhat test --coverage
# Or only Solidity tests
npx hardhat test solidity --coverage

This instrumentation happens at compile time and works across solc versions, but remember that coverage bytecode differs from production; don’t use coverage builds for gas baselines. (hardhat.org)

Example: Fork mainnet and impersonate an address inside a test

import { test, expect } from "node:test";
import { defineConfig, network } from "hardhat";
import { setBalance, impersonateAccount } from "@nomicfoundation/hardhat-network-helpers";

test("whale transfer on a fork", async () => {
  await network.create({ // Hardhat 3 Network Manager API
    forking: { url: process.env.MAINNET_RPC!, blockNumber: 20800000 }
  });

  const whale = "0x1234...abcd";
  await impersonateAccount(whale);
  await setBalance(whale, 10n ** 21n); // 1000 ETH in wei

  const { ethers } = await network.connect();
  const signer = await ethers.getSigner(whale);
  await signer.sendTransaction({ to: await signer.getAddress(), value: 1n }); // noop send
});

The same flow works with Ethers or Viem; helpers wrap JSON‑RPC methods like hardhat_impersonateAccount and hardhat_setBalance. Use a pinned blockNumber for deterministic CI. (hardhat.org)

When Hardhat is the better default

  • You need TypeScript end‑to‑end tests, a rich plugin ecosystem (linting, verification, coverage, gas, TypeChain), or declarative deployments (Ignition) that your DevOps team can reason about. (hardhat.org)

Emerging practice: secure your plugin supply chain

  • Pin exact versions of community plugins in package.json, and monitor advisories. Notably, an ENS‑namespaced “hardhat‑toolbox‑viem‑extended” package was flagged for malicious preinstall behavior in Nov 2025; avoid unvetted forks of official packages. (advisories.gitlab.com)

Foundry 1.x, concretely (2025 state)

Foundry is a Rust‑based toolchain designed for speed and Solidity‑first testing:

  • forge: unit, fuzz, invariant tests; integrated gas report and coverage; interactive debugger; CI‑friendly. (getfoundry.sh)
  • anvil: fast local EVM with RPC forking, impersonation, blob/KZG and beacon endpoints, and Hardhat‑compatible custom JSON‑RPC methods. (getfoundry.sh)
  • chisel: a Solidity REPL to try code snippets without scaffolding a project. (getfoundry.sh)
  • Performance: official benchmarks show noticeable improvements across builds/tests; Paradigm’s v1.0 announcement reports 2.1–5.2× faster compilation vs. Hardhat in their library benchmarks (methods vary; validate against your codebase). (getfoundry.sh)

Example: A minimal invariant test that should hold across random sequences

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

import "forge-std/Test.sol";

contract Vault {
    mapping(address => uint256) public balance;
    function deposit() external payable { balance[msg.sender] += msg.value; }
    function withdraw(uint256 amount) external { require(balance[msg.sender] >= amount, "insufficient"); balance[msg.sender] -= amount; (bool ok,) = msg.sender.call{value: amount}(""); require(ok); }
}

contract VaultInvariants is Test {
    Vault vault;
    function setUp() public { vault = new Vault(); }

    // Handlers: forge will randomize callers and inputs on target contracts
    function invariant_totalConserved() public {
        // Sum of all balances must equal contract balance
        // (for brevity, we only check caller's view and contract balance here)
        assertEq(address(vault).balance, vault.balance(address(this)));
    }
}

Run:

forge test --mt invariant_ --ffi -vvv

Use

[invariant] runs
and
depth
in foundry.toml to scale campaigns, and prefer invariants that reflect conservation or monotonic properties. Foundry exposes explicit invariant config and supports fuzz shrinking. (learnblockchain.cn)

Example: Gas snapshots and coverage you can gate in CI

# Produce and diff gas snapshots across PRs
forge snapshot --check --tolerance 1

# Coverage summary/LCOV for CI
forge coverage --report summary --report lcov

Snapshots enable PR budgets (e.g., ±1% tolerance), and LCOV can feed CI dashboards. (getfoundry.sh)

Example: Deterministic mainnet‑fork test with impersonation

anvil --fork-url "$MAINNET_RPC" --fork-block-number 20800000 --auto-impersonate

Then, in your test:

vm.startPrank(0x1234...abcd); // impersonate a whale
// ... exercise protocol paths ...
vm.stopPrank();

Anvil mirrors Hardhat’s impersonation semantics and adds convenience flags like --auto-impersonate. Pin the fork block for reproducibility. (getfoundry.sh)

When Foundry is the better default

  • You value short test cycles, native fuzz/invariant testing, or auditor‑style workflows with Solidity‑first tests, cheatcodes (vm.prank, vm.warp, vm.roll, vm.deal, vm.mockCall), and no Node.js overhead. (getfoundry.sh)

“Ape,” Brownie, and other frameworks you’ll be asked about

  • Ape (Python): modern, plugin‑based CLI with multi‑network sessions (local, testnet, mainnet), tracing, gas reporting, and Jupyter integration. Good fit for Python quant teams and data science notebooks. (apeworx.io)
  • Brownie: still used in legacy stacks, but explicitly “no longer actively maintained.” If you need Python today, choose Ape or run Foundry/Hardhat from Python scripts. (pypi.org)

Security testing stack: beyond unit tests

High‑assurance teams pair their framework with three classes of security tooling:

  1. Static analysis (fast, cheap gates in CI)
  • Slither: modern detectors, GitHub Action, SARIF output for code scanning; supports custom plugins and fail‑on severity thresholds. Add as a required check. (github.com)
  1. Property‑based fuzzing (find logic bugs early)
  • Foundry: native fuzz/invariant testing (unit + stateful). Use invariants for supply conservation, AMM invariants, permission models, and escrow accounting. (learnblockchain.cn)
  • Echidna (Trail of Bits): standalone property fuzzer with GitHub Action and shrinking; great to cross‑check Foundry invariants. (github.com)
  1. Symbolic/concolic analysis (deeper but costlier)
  • Manticore (Trail of Bits) and Mythril (ConsenSys Diligence): explore paths symbolically; useful on complex auth/pause/upgrade logic or where fuzzing struggles. (github.com)

Example: Minimal CI matrix (GitHub Actions)

name: ci
on: [push, pull_request]
jobs:
  slither:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: crytic/slither-action@v0.4.1
        with:
          fail-on: medium
  foundry:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: curl -L https://foundry.paradigm.xyz | bash
      - run: foundryup
      - run: forge build
      - run: forge test --gas-report
      - run: forge coverage --report summary
  hardhat:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npx hardhat test --coverage

This gives you static gates (Slither), fast fuzz/unit checks (Foundry), and TS integration + coverage corroboration (Hardhat). Tune fail‑on severities and gas/coverage thresholds per repo. (github.com)


Hardhat vs. Foundry head‑to‑head: what matters in practice

  • Speed
    • Foundry typically compiles/tests faster (Rust + native tooling). Expect 2–5× compile gains in library‑heavy repos, with variance by codebase and cache strategy. Validate with your own CI runners. (paradigm.xyz)
  • Test depth
    • Foundry’s built‑in fuzz/invariant suite and cheatcodes lower the effort to write deep property tests; Hardhat achieves similar depth via plugins or external tools. (getfoundry.sh)
  • Ecosystem integration
    • Hardhat’s toolbox model (Viem/Ethers, TypeChain, gas reporter, verification) and Ignition deployments integrate smoothly with TypeScript stacks and infra pipelines. (hardhat.org)
  • Debuggability
    • Hardhat’s Solidity console.log plus stack traces remain pragmatic; Foundry offers traces, an interactive debugger, and Chisel for on‑the‑fly REPL experiments. (hardhat.org)
  • Fork testing
    • Both support forking and impersonation; Anvil adds convenient flags; Hardhat has ergonomic Network Helpers and the Network Manager API in v3. Pin block numbers for reproducible CI. (getfoundry.sh)

Practical patterns you can adopt this quarter

  1. Hybrid repo layout for speed and ergonomics
  • Keep a Foundry project at the root for Solidity tests, fuzzing, invariants, gas snapshots, and coverage.
  • Keep a Hardhat subproject for TypeScript integration tests, plugin‑based checks (linters, gas reporter), verifications, and Ignition deploy modules.

Directory sketch:

/contracts
/foundry.toml
/test (Foundry .t.sol)
/script (Foundry deploy/scripts)
/hardhat
  hardhat.config.ts
  ignition/modules/*.ts
  test/**/*.test.ts

Use Foundry’s --hardhat layout flag if you need to reuse node_modules. (getfoundry.sh)

  1. CI thresholds that actually fail when they should
  • Foundry:
    forge snapshot --check --tolerance 1
    to prevent silent gas regressions;
    forge coverage --report summary
    with minimum line/branch targets.
  • Hardhat:
    npx hardhat test --coverage
    ; set minimum coverage in your linter/PR checks; use gas‑reporter with Etherscan API v2 to track L1/L2 costs across PRs. (getfoundry.sh)
  1. Deterministic fork harnesses
  • Choose one RPC provider, pin block numbers, and pre‑warm dependent contract addresses (token whales, oracles, timelocks). Both Anvil and Hardhat Network expose impersonation and state mutators; wrap them in helpers so tests don’t drift. (getfoundry.sh)
  1. Defense‑in‑depth testing
  • Write at least three invariants per critical contract: conservation, authorization, and bounds (e.g., slippage/price bounds). Cross‑run invariants with Foundry and Echidna to catch generator biases. Add Slither as a required CI gate; run Mythril/Manticore selectively on upgradeable proxies, AMMs, or bespoke math. (learnblockchain.cn)
  1. Supply‑chain hygiene
  • Allowlist official @nomicfoundation plugins, pin exact versions, and audit any extended toolboxes. The November 2025 “Shai‑Hulud 2.0” npm campaign is a reminder to scrutinize package origins, especially around the Viem ecosystem. (advisories.gitlab.com)

Brief, in‑depth notes on emerging details

  • Hardhat coverage now “just works” with Solidity tests and Node’s test runner for TypeScript when using the Viem toolbox; you no longer need to bolt on third‑party coverage for basic scenarios. This reduces configuration drift across teams. (hardhat.org)
  • Ignition’s deployment journals (journal.jsonl) enable safe resume on flaky RPCs and track per‑network contract addresses in ignition/deployments, which is easier to reason about than bespoke scripts. Fee bumping and confirmation thresholds are configurable per network. (v2.hardhat.org)
  • Foundry’s coverage and gas tooling are now first‑class:
    forge coverage
    supports LCOV output; gas snapshots integrate with PR diffs; flamegraphs/charts help isolate hot paths when optimizing. (getfoundry.sh)
  • Anvil surfaces Hardhat‑compatible RPC extensions, adds blob/KZG and beacon endpoints helpful for post‑Dencun testing, and supports auto‑impersonation for forked tests. (getfoundry.sh)
  • Training your org: developers with a web/TS background ramp faster on Hardhat; auditors and Solidity‑heavy teams often prefer Foundry. The 2024 Solidity survey shows Foundry overtook Hardhat in usage among respondents (51.1% vs. 32.9%), but your team’s stack and hiring pipeline should drive the choice. (soliditylang.org)

Migration guidance (Truffle/Ganache, Brownie)

  • From Truffle/Ganache: migrate to Hardhat (Ignition deploys, Toolboxes) or Foundry (forge scripts + broadcast). Plan to re‑establish coverage/gas pipelines and mainnet‑fork tests; don’t lift‑and‑shift brittle scripts. (consensys.io)
  • From Brownie: acknowledge maintenance status and migrate to Ape if you must stay in Python; otherwise consolidate on Foundry/Hardhat and expose minimal Python shims for data science use. (pypi.org)

Decision checklist

Choose Hardhat 3 if:

  • Product org is TS‑native; you want Ignition’s declarative deployments; you value built‑in coverage and a large plugin catalog. (hardhat.org)

Choose Foundry if:

  • You need very fast feedback loops, native fuzz/invariants, and Solidity‑first ergonomics for audits and high‑assurance protocols. (learnblockchain.cn)

Choose a hybrid if:

  • You want the speed and depth of Foundry with the ecosystem/infra integrations of Hardhat. This is the most common enterprise setup we see in 2025. (getfoundry.sh)

What we recommend at 7Block Labs

  • Default to a hybrid stack: Foundry for unit/fuzz/invariant testing and gas/coverage baselines; Hardhat 3 + Viem toolbox for TS tests, verification, and Ignition deployments; Tenderly or Anvil forks for E2E. Gate PRs on Slither (medium+), coverage minimums, and ±1% gas drift. (hardhat.org)
  • Codify reproducibility: pin fork block numbers, solc versions, and plugin versions; generate LCOV and gas snapshots in CI; store Ignition journals in artifacts storage. (v2.hardhat.org)
  • Run a quarterly tool audit: update to the latest Hardhat/Foundry releases, rotate Etherscan API config for gas‑reporter v2, and scan dependency trees for advisories. (github.com)

If you’d like a hands‑on pilot, we can deliver a two‑week “Testing Modernization Sprint” that ports your top‑risk contracts, lands CI gates, and leaves your team with a repeatable playbook tailored to your stack.


Appendix: quick references

  • Hardhat 3 coverage and Viem toolbox (official docs). (hardhat.org)
  • Ignition guides and artifacts. (hardhat.org)
  • Hardhat Network reference (forking, impersonation, state edits). (v2.hardhat.org)
  • Foundry coverage/gas snapshot/cheatcodes references. (getfoundry.sh)
  • Slither/Echidna/Manticore/Mythril. (github.com)
  • Truffle/Ganache sunset; Brownie maintenance status. (consensys.io)

7Block Labs helps startups and enterprises design, build, and harden blockchain software. If this guide helped you pick a direction, we’re happy to review your repo and propose a crisp migration plan tailored to your timelines and risk posture.

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.