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:
- 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)
- 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)
- 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
- 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)
- CI thresholds that actually fail when they should
- Foundry:
to prevent silent gas regressions;forge snapshot --check --tolerance 1
with minimum line/branch targets.forge coverage --report summary - Hardhat:
; set minimum coverage in your linter/PR checks; use gas‑reporter with Etherscan API v2 to track L1/L2 costs across PRs. (getfoundry.sh)npx hardhat test --coverage
- 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)
- 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)
- 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:
supports LCOV output; gas snapshots integrate with PR diffs; flamegraphs/charts help isolate hot paths when optimizing. (getfoundry.sh)forge coverage - 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.

