Image
Build
Connect & operate
Design & teams
Start hereScope a build in one callBring a spec, a wireframe, or a paragraph. You leave with an architecture, a timeline, and a number.Book a scoping call
AI software
LLM & data systems
Vibe coding
Ready to ship?Put AI where the work isAgents, RAG, and private LLMs wired into the systems your team already uses — not a chatbot bolted to a homepage.Discuss an AI project
Domain firstWe learn your workflow before we model itRegulated, operational, or high-volume — the constraints belong in the schema, not in a training doc.Talk about your domain
Plan smarterEstimate before you commitCost ranges, scope templates, and the questions we ask in discovery — free, no form.Open the cost calculator
Real conversationsTalk with a technical leadNo SDR, no discovery gauntlet. The person on the call is the one who scopes the build.Book a call
Eric Lamanna
Author
How to Unit Test Solidity Smart Contracts with Foundry (Fast & Reliable) — featured image
9/25/2026

How to Unit Test Solidity Smart Contracts with Foundry (Fast & Reliable)

Smart contracts do not forgive sloppy thinking. One off-by-one error and you are staring at a wallet balance that looks like a bad joke. Foundry makes that nightmare less likely by giving you a fast, ergonomic testing toolkit that feels built for Solidity rather than glued on. 

If you want lean feedback loops and trustworthy coverage in software development, Foundry keeps your eyes on the code and your mind off the tooling. The result is a workflow that encourages more tests, better tests, and fewer midnight incidents.

Why Foundry Deserves a Seat in Your Toolbelt

Foundry is purpose built for the EVM world. You write tests in Solidity, right next to the contracts they validate. That small design choice matters. You think in the same language as your code, you use the same types, and you avoid context switching into a different runtime. 

The CLI is compact and expressive, the defaults are sensible, and the stack gets out of your way. When the tools are frictionless, you run tests more often, which means you catch subtle bugs before they grow teeth.

How Foundry Speeds Up Feedback Loops

Most tools promise speed. Foundry actually feels fast. Test runs compile only what changed, caching everything they can. Logs are crisp, stack traces are readable, and the command output points to the exact line that betrayed you. Speed is not only about clock time, it is about cognitive momentum. Quick cycles keep your mental model warm so you can refactor, re-run, and refine without losing the plot.

Blazing-Fast Compiles and Runs

forge test is the heartbeat of Foundry. It compiles with pragmas respected, optimizes aggressively when asked, and runs test suites with minimal ceremony. Even large projects feel snappy. When a test fails, Foundry prints the key data first, so you do not hunt through a wall of noise. That tiny detail saves seconds per failure, which adds up to real flow state.

Test Suite Run Time by Compile ModeFoundry's caching turns a routine test run into a near-instant feedback loop42sClean rebuild(forge clean)28sCold compile(no cache)3sIncremental(cached)

Snapshotting and Forensics

Complex failures can be hard to reproduce. Foundry’s snapshots let you freeze the chain state, then replay from that moment while you poke variables and try different paths. You can print events, decode return data, and capture traces that illuminate exactly why the call sequence fell apart. After a few minutes of this, problems that looked mysterious will feel obvious.

What you needFoundry featureWhat it changesWhy it feels fasterTypical command
Quick iterationIncremental compiles + cachingRebuilds only what changed instead of redoing everything.Your mental model stays warm—edit, run, repeat without losing the plot.forge test
Readable failuresCrisp logs + useful stack tracesPoints to the exact line that failed, without a wall of noise.Less “where did it break?” time, more “why did it break?” time.forge test -vv
Fast signal firstFailure output prioritizes key dataShows the important values early so you don’t dig for clues.Saves seconds per failure—compounds into real flow state.Lower debugging friction
Forensics on tricky bugsSnapshots + tracesFreeze chain state, replay, and inspect call sequences.Turns “mystery failures” into reproducible, step-by-step evidence.forge test -vvvv
Confidence without waitingShort-running suites encourage frequent testsYou run tests constantly instead of batching them “later.”Bugs get caught when they’re small—before they grow teeth.More tests, earlier
Momentum in refactorsFast reruns keep feedback tightRefactor → rerun → confirm is measured in seconds.You stay brave: less fear of breaking things, more willingness to improve them.forge test –match-test testName

Project Setup Without the Headaches

Getting started should not feel like assembling flat-pack furniture without instructions. With Foundry, you forge init, choose a template or keep it minimal, and begin writing tests. Dependencies, like common libraries and cheatcodes, are straightforward to add. You get a tidy project structure with a src for contracts and test for tests. In other words, everything goes where you expect, which keeps the codebase navigable as it grows.

Writing Tests That Actually Catch Bugs

Brittle, shallow tests give a comforting but false sense of safety. Foundry encourages tests that exercise the contract from the outside in, using behavior as the guide. Think about the invariants that must always hold, then write tests that try to break them. Use clear naming for test functions, narrate the story in code comments, and make each assertion meaningful. Your future self will thank you.

Arrange, Act, Assert in Solidity

The Arrange, Act, Assert pattern translates neatly to Solidity tests. First, set up the state so the story makes sense. Then, perform the action under scrutiny, such as a transfer or mint. Finally, assert on the resulting state, events, and balances. Keeping this rhythm helps you avoid tests that mix high-level setup with low-level checks, which often hides bugs. It also makes failures easier to reason about because you know exactly where to start looking.

Fuzzing to Shake Out Edge Cases

Human imagination is limited. Fuzzing gives you a patient robot that tries weird inputs all day. Foundry includes property-based testing that feeds randomized values into your functions while checking that your assertions still hold. This flushes out corner cases like zero values, large numbers that push storage boundaries, and combinations your brain decided were “probably fine.” The best part is how little boilerplate you need to get meaningful mileage from it.

Invariants to Guard Core Assumptions

Invariants describe truths that must never break, no matter how chaotic the sequence of calls. Wallet totals may need to remain constant, ownership should never transfer without a valid signature, and collateral ratios should not dip below a minimum. Foundry’s invariant testing walks your contract through many paths, looking for even a single state where your rules fail. If the invariant breaks, you get a reproducible trace that leads you straight to the culprit.

Branch Coverage: Unit Tests Alone vs. Fuzzing + InvariantsRandomized inputs and invariant checks catch what hand-written cases miss61%97%Core transferlogic55%92%Accesscontrol40%98%Edge-casearithmeticUnit tests only+ Fuzzing & invariants

Handling Time, Ether, and Callers

Smart contracts often depend on the caller, the value of msg.value, or block time. Tests must control these to be meaningful. Foundry’s cheatcodes make it simple. You can prank a specific address, warp time forward, and simulate a call with exact value. 

This lets you test conditions like cooldown periods, interest accrual, or access checks with surgical precision. Instead of mentally simulating miners and clocks, you write explicit tests that prove the behavior beyond doubt.

Mocking External Calls Without Tears

On-chain systems rarely live alone. Your contract might consult a price feed, call a token, or ping a registry. In tests, you need to replace those neighbors with predictable stand-ins. 

Foundry’s facilities for mocking return values and reverting paths make it easy to simulate both happy paths and glorious failures. You can make a dependency behave, misbehave, or pretend to be offline. If your contract survives the bad neighborhoods you invent, it is ready for the real world.

Gas, Coverage, and Reporting You Can Trust

Performance matters. Foundry surfaces gas costs per function and per test, which turns optimization into a game you can win. When you tweak a loop or change a data structure, you immediately see whether it saved gas or just shuffled deck chairs. 

Coverage reports show which lines your tests actually executed. If a critical branch is untouched, you will see it. This combination of visibility and measurability nudges you toward safer code with less wasted computation.

Gas Cost Before vs. After OptimizationFoundry's per-function gas reporting turns tuning into a measurable game5120029800transfer()6840041200mint()4670028900approve()BeforeAfter

CI That Does Not Make You Wait

Continuous integration should catch regressions before they land in main. Foundry’s speed makes it perfect for CI pipelines that run often. A simple workflow runs tests on every pull request, with a separate job for fuzzing and invariants at higher iteration counts. 

The fast suite gives quick feedback to developers, while the heavier suite runs in parallel to catch deeper issues. The whole process feels responsive rather than punitive, which means people keep it green.

Common Gotchas and How to Dodge Them

Reentrancy is the riddle that never gets old. Use tests that simulate callbacks at inconvenient moments, then assert that state stays consistent. Arithmetic overflow is less dramatic since Solidity 0.8, but explicit checks still clarify intent. Pay attention to storage layout when upgrading contracts, and add tests that prove the new version reads old data correctly. Finally, test access control carefully. A single missing modifier can turn a vault into a vending machine.

Team Habits That Multiply Quality

Tools shape habits, and habits shape codebases. Create a culture where writing tests is not extra credit but part of building a feature. When someone proposes a change, ask which tests prove it is safe. Keep test files as clean as production code, since they are permanent residents, not temporary scaffolding. Review tests with the same curiosity you bring to contract logic. If the tests are precise, descriptive, and thorough, the code they guard will inherit those virtues.

Designing for Testability From Day One

You can smell testable code. It avoids unnecessary global state, isolates external calls behind clear interfaces, and keeps functions small and purposeful. When you design with testability in mind, Foundry becomes a playground rather than a chore. 

You can assert on events instead of scraping logs, you can swap mocks for real dependencies with no drama, and you can measure the collateral effects of a single line change without guesswork. Good design makes good tests almost inevitable.

Bringing It All Together

A healthy Foundry workflow often looks like this. You outline the behavior and invariants for a new feature, write a few happy-path tests, then add fuzzing to explore the unknowns. You sprinkle in negative tests that prove the contract rejects bad inputs with the right error messages. 

You wire up mocks for external calls, then measure gas to keep things lean. Once green locally, the CI runs the quick suite and the deeper invariant checks. By the time you push to production, the code has survived a small storm of well-aimed tests.

Why This Approach Feels Calmer

Speed and clarity reduce anxiety. When your tests run in seconds, you experiment freely. When your assertions are expressive, you understand failures instead of fearing them. When your coverage is honest, you know where the holes are, which means you can fix them instead of hoping they do not matter. Foundry’s biggest gift is psychological. It takes a domain that can feel twitchy and makes it feel manageable, almost friendly.

The Payoff You Actually Notice

The tangible results arrive quickly. Fewer regressions sneak into releases. Gas costs trend downward rather than upward. On-call pages taper off. Reviews shift from basic safety questions to real design discussions. The velocity of change increases without increasing risk. You stop dreading refactors because your tests give you a safety net that is both wide and strong. Good tests make better code possible, and Foundry makes good tests pleasant to write.

Conclusion

Foundry brings Solidity testing to a place that feels natural, quick, and precise. By writing tests in the same language as your contracts, leaning on fuzzing and invariants, controlling time and callers, and keeping gas and coverage visible, you build confidence that does not wobble under pressure. 

Add fast CI and a few disciplined team habits, and you get a quality pipeline that scales with your ambition. The tools stay quiet, the code speaks clearly, and your smart contracts behave like they have good manners.

Author
Eric Lamanna
Eric Lamanna is a Digital Sales Manager with a strong passion for software and website development, AI, automation, and cybersecurity. With a background in multimedia design and years of hands-on experience in tech-driven sales, Eric thrives at the intersection of innovation and strategy—helping businesses grow through smart, scalable solutions. He specializes in streamlining workflows, improving digital security, and guiding clients through the fast-changing landscape of technology. Known for building strong, lasting relationships, Eric is committed to delivering results that make a meaningful difference. He holds a degree in multimedia design from Olympic College and lives in Denver, Colorado, with his wife and children.