A few years back I worked on a reporting feature that hit every acceptance criterion in the ticket. Every field matched the spec, every calculation was correct according to the documented formula, every edge case in the ticket was handled. QA signed off. Then it shipped, and the first support ticket came in within a day: the numbers were "technically right" but useless, because the spec itself had been written against an old version of how the business actually calculated that metric. Nobody had checked with finance before writing the ticket.
That's verification and validation in one story. We verified the software matched the spec perfectly. Nobody validated that the spec matched what the business actually needed. Both matter, they're not interchangeable, and mixing them up is one of the more expensive mistakes a team can make without realizing it's happening.
Verification: are we building it right?
Verification asks whether the software conforms to its specification, requirements, or design documents. It's internal-facing - you're checking the product against what was written down, not against what anyone actually wants.
This covers most of what people think of as "testing" day to day:
- Code reviews checking implementation against a design doc
- Unit and integration tests checking behavior against documented requirements
- Static analysis, linting, spec-conformance checks
- QA walking through a ticket's acceptance criteria one by one
Verification is good at catching a specific kind of bug: the gap between what was specified and what got built. It's terrible at catching a different kind of bug: the gap between what was specified and what should have been specified in the first place. My reporting story is a verification success and a validation failure, and verification alone had no way of flagging that.
Validation: are we building the right thing?
Validation asks whether the software actually satisfies the real-world need it's meant to serve, regardless of what the spec says. It's external-facing - checking against reality, users, and business intent, not against a document.
This looks more like:
- User acceptance testing with actual users, not just QA reading a checklist
- Beta releases and real usage data
- Product and stakeholder review against the actual problem being solved, not just the ticket
- Watching what happens when real traffic hits the thing, not just the scenarios someone thought to write down
Validation is where "it passed every test" and "it's ready to ship" turn out to be different sentences. A feature can be verified into oblivion - every acceptance criterion green, and still fail validation the moment a real user tries to do something the spec author never considered.
Why the mix-up is expensive, not just academic
Teams that only verify tend to over-trust their test suite. A hundred passing tests feels like safety, but if every one of those tests was written against a spec that had a gap, you've built a very well-tested version of the wrong thing. The bug isn't in the code. It's upstream, in the requirements, and no amount of additional unit testing against those same requirements will ever catch it.
This is also why "we have great test coverage" and "our users are happy" aren't the same claim, and teams get bitten when they treat the first as proof of the second. Coverage measures verification. It says nothing about validation.
The verification toolbox, and what each piece actually catches
It's worth breaking "verification" down further, because the different techniques catch genuinely different classes of mismatch:
Static verification happens before anything runs: code reviews, design reviews, static analysis, linting, type checking. These catch structural problems - a function that doesn't match its documented contract, a data flow that violates an assumption elsewhere in the system, a design that technically satisfies a requirement but contradicts another one nobody cross-checked. Cheap to run, cheap to fix at this stage, and the earlier a mismatch is caught here, the less it costs later.
Dynamic verification is everything that runs the code against expected behavior: unit tests, integration tests, contract tests, regression suites. This is where most engineering time goes, and for good reason - it's fast, repeatable, and automatable in a way static review isn't. But it's bounded by the same limitation every time: it can only check the code against what someone wrote down as "expected." A dynamic test suite with high branch coverage against an incomplete spec is still just thoroughly verifying the wrong thing.
Formal verification - proving a program correct against a formal specification using mathematical methods, sits at the far end and is mostly reserved for places where a bug is catastrophic: aerospace, medical devices, cryptographic protocols, safety-critical embedded systems. Most teams will never need it, but it's worth knowing it exists, because it makes the boundary clearer: even a mathematically proven-correct program is only proven correct relative to its spec. If the spec encodes the wrong requirement, formal verification will prove the wrong thing flawlessly.
The pattern across all three: verification techniques get more rigorous as you move from static review to formal proof, and none of them, at any level of rigor, can tell you whether the specification itself reflects reality. That gap only closes through validation.
The validation side, and why it resists automation
Validation techniques look different because they're checking against something inherently fuzzier than a spec:
User acceptance testing (UAT) puts the software in front of actual users or close proxies (product owners, domain experts) and asks whether it does what they need - not whether it matches a document. UAT frequently surfaces requirements gaps that were invisible during verification, because the people testing aren't checking a checklist, they're trying to accomplish something.
Beta programs and staged rollouts extend this to real usage at scale, which matters because individual UAT sessions still can't replicate the variety of how a broad user base actually behaves. A feature can sail through UAT with five friendly testers and still collapse against the messiness of real users doing things nobody anticipated.
Production monitoring and incident analysis is validation that never stops. Every bug report, every confused support ticket, every unexpected usage pattern is a live signal about whether the system satisfies the real need - arguably a more honest signal than any pre-release testing phase, because it's coming from reality instead of a simulation of it.
Domain and stakeholder review - going back to the people who understand the actual problem, not just the ticket, and asking whether this solves what they actually needed - is the least technical and most frequently skipped form of validation, and it's often the one that would have caught my reporting-feature story before it reached a user.
The common thread: validation techniques resist full automation because they're checking against a moving, real-world target rather than a fixed document. You can automate a regression suite. You can't fully automate whether something still makes sense to the humans using it, and teams that try to substitute more verification for that keep rediscovering the gap the hard way.
A rough way to think about where each one belongs
Verification tends to live close to the code - the earlier and more automatable, the better, because it's checking against something explicit and stable (a spec, a contract, a set of requirements). This is where automated test suites earn their keep: fast, repeatable checks that the implementation still matches what was agreed on.
Validation tends to need something verification can't provide on its own: exposure to reality. Real users, real traffic, real edge cases nobody thought to write into a ticket. This is also where a lot of teams under-invest, because it's harder to automate and harder to feel "done" with - there's no green checkmark for "definitely building the right thing," only ongoing signal from actual usage.
Verification and validation in software testing, does not substitute each other. A team that's excellent at verification and weak at validation ships well-tested products nobody needed exactly as specified. A team that's strong on validation but sloppy on verification ships the right idea built on a shaky, bug-prone foundation. The healthiest setups treat them as two different questions, asked continuously, rather than one "testing" phase that's supposed to cover both.
Next time a feature passes every test and still gets a confused reaction from users, it's worth asking which of the two actually failed. Usually it's not the tests.
Top comments (0)