ProductHow it worksPricingBlogDocsLoginFind Your First Bug
A dark matte 3D toy frog sits astride a single long charcoal machined rail running edge to edge, resting one hand on a solid lime cube on the rail and holding a hollow lime wireframe cube below it, with solid and wireframe cubes alternating along the same rail
TestingVerification And ValidationAcceptance Testing

Why 2 Questions Define Verification vs Validation

Tom Piaggio
Tom PiaggioCo-Founder at Autonoma

Verification vs validation in software testing asks two separate questions about the same build. Verification checks the system against its own spec, using reviews, static checks, and any test derived from the code. Validation checks the system against what the user actually needed, since no written spec can answer that question. The decision rule, known together as V&V, is simple: if what's being checked against is written down inside the system, that's verification; if it's a person's behavior or judgment, it's validation. Both halves can run on the same commit.

A pull request lands with three checks attached. A reviewer approves it, the type checker passes, and an AI-generated end-to-end test goes green against the build. Ship it? That question turns out to hinge on something none of the three checks name out loud: which of two different questions each one was actually answering.

This is written for the engineer, SDET, or release owner deciding whether a build ships, or the person who was just told to name and run the gate that decides it. It is not written for someone designing a QA team's suite-allocation strategy, someone asking whether an AI-generated suite is testing anything real, or someone choosing edge-case inputs for a single test case. Those are real questions; the software testing terminology guide sorts them into their own place, one level down from this one.

What Verification and Validation Actually Ask

What Is Verification in Software Testing?

Both terms get defined constantly and applied inconsistently, which is a different problem than not having a definition at all. The pairing itself isn't a marketing convention: IEEE 1012-2024 is the active standard defining V&V processes as determining whether a system's development products conform to the requirements of their own activity, and separately, whether the finished product actually satisfies its intended use and its users' needs. Verification checks a system against its own specification: does the code do what the design, the ticket, or the interface contract said it should do. A code review is verification. A static type check is verification. A unit test that calls a function and checks the return value against what the function was documented to return is verification. None of these look outside the system for their answer. The spec is right there in the code, the types, or the ticket, so verification can be a closed loop.

What Is Validation in Software Testing?

Validation checks a system against something outside itself: the person who is going to use it. Does this actually solve the problem, in a way a person recognizes as correct, not just technically compliant. A beta program is validation. An exploratory session, where someone with judgment pokes at a feature because something felt off, is validation. A user interview after a release is validation. None of these have a spec to check against. The only oracle is a person's judgment, which is why validation can't be automated away no matter how good the tooling gets.

Put those two ideas next to each other and the load-bearing distinction states itself: verification asks whether we built it right, against the spec; validation asks whether we built the right thing, against the user. The first is cheap to generate, because a machine can read a spec. The second is where human judgment stays, because judgment about what a user needed was never written down anywhere a machine can read it.

One lifecycle, two questionsVerification above the line, validation belowVerificationValidationTimeCode reviewVerificationType checkVerificationUnit testVerificationE2E run, liveVerificationExploratory testValidationBeta usersValidation

Six activities on one lifecycle. Verification clusters early and cheap; validation shows up wherever judgment is scarce.

That's the artifact most pages in this space skip. They draw verification down one column and validation down the other, which never tells you which column the check you actually run belongs to. Put every real activity on one lifecycle instead, and the two questions stop looking like phases and start looking like what they are: two different things you can ask about the same build, at the same time.

If you're the one deciding whether today's build clears the gate, or you were just handed that decision, the rest of this article is written for you. If you're allocating a QA org's suite strategy across a quarter, that's a different page, and a longer one.

Why the Incumbent Advice Rations Validation to the End

The canonical advice says something close to this: verification happens throughout development through reviews and static checks, and validation happens once, near the end, through an expensive end-to-end pass against the finished product. That advice isn't wrong. It hides an assumption nobody states out loud. Running the actual system, end to end, against real user behavior, used to require a person clicking through it by hand. Human labor is expensive and slow, so validation got rationed to a single late phase precisely because nobody could afford to run it constantly.

Why validation got rationedThe assumption nobody namedSequential modelVerification stays cheapEvery commitValidationExpensiveand lateRationed to one passContinuous modelVValVValVValVValVValV is verification, Val validation

Sequential rations validation to one expensive pass. Continuous runs both, together, on every commit.

Once running the real system stops requiring a person to click through it by hand, the phase boundary stops making sense on its own terms. Nothing about validation's definition ever required it to run late. It ran late because it was expensive, and the moment that stops being true, verification and validation are free to run on the same schedule instead of taking turns.

When Both Questions Run Per Commit

This is the same shift shift-left testing has been gesturing at for years: pull the expensive stage earlier instead of leaving it stranded at the end. Shift-left, on its own, only says to move validation earlier. It doesn't say what a machine is actually checking when it runs an automated end-to-end pass on every pull request instead of once before release, and that turns out to be the more interesting question.

An AI-generated end-to-end check is derived from the codebase: an agent reads the routes, the components, and the flow, and writes a check that confirms the code does what the code already says it should do. That check can be genuinely useful. It is also, structurally, verification. It was never derived from what a user needed. It was derived from what the code claims to do. Run it against a build that faithfully implements the wrong feature, and the check passes every time, because passing was defined entirely in terms of the code it came from. A suite can go fully green and still not have validated anything a user would recognize as correct, which is exactly the gap between a passing check and a validated feature.

Which question is it answeringTrace the check to its sourceCodebaseAI-generatedcheckVerificationvsHuman intentCheck fromintentValidation

Same shape of check, different source of truth. One traces to the code, the other traces to a person.

That's not an argument against AI-generated checks. It's an argument for labeling them correctly. A check that traces back to the codebase is verification wearing validation's clothes, useful for exactly what verification is useful for, and not a substitute for the judgment call only a person can make about whether the feature was the right one to build.

Verification vs Validation, Activity by Activity

Six concrete activities, placed on the lifecycle above, land on one question or the other for a specific reason: what they check the build against, and who or what is actually doing the checking.

ActivityAnswersChecked againstPerformed by
Code reviewVerificationSpec or ticketHuman reviewer
Static type checkVerificationType contractCompiler or linter
Unit testVerificationDocumented function behaviorTest runner
AI-generated E2E checkVerificationThe code it was derived fromAI test agent
Exploratory sessionValidationTester's own judgmentQA engineer
Beta with real usersValidationReal user behaviorProduct or support team

Read down the third column and the pattern holds regardless of who or what runs the check: whenever the thing being checked against is written down somewhere inside the system, code, types, a documented return value, that's verification. Whenever it's a person's behavior or a person's judgment, it's validation. Nothing about automation moves an activity from one column to the other. Automation just changes how fast the verification column runs.

That pattern also explains why a smoke gate and a beta program never compete for the same slot on a release calendar. A team debating whether to run "smoke or validation" this sprint is really asking whether the code is stable enough to touch at all, which a shallow check can answer in minutes. Validation asks something speed can't shortcut: does a real person, using the real product, get what they expected. Rushing an answer to that second question doesn't make automation catch up to it. It just moves the risk from before release to after it, in production, in front of a user who never signed up to find the gap.

How Autonoma Generates Verification and Concentrates Validation

Most teams either hand-write and hand-maintain a verification suite that goes stale within a release cycle, or they skip writing one at all and let every regression surface as a support ticket days after a user hits it. Either way, the scarce resource, a person's attention, ends up spent rewriting checks a machine could regenerate, instead of on the beta feedback and exploratory sessions that only a person can run.

Our agents read the codebase directly, the same way the table above assumes a verification check should be read: from the routes, the components, and the flows that already exist, not from a script someone wrote once and forgot to update. Those agents generate end-to-end checks from that reading and run them against a running build of the application, not a saved snapshot of the DOM, which is what lets a check survive a UI change instead of breaking the moment a layout shifts. On every pull request, the Diffs Agent re-reads what changed and updates the suite accordingly, so the verification half of the lifecycle regenerates itself instead of drifting out of date. None of that is a benchmark claim about speed or coverage; it's an architecture choice, reading the codebase and checking against the running application, built specifically so the verification column in the table above stops being something a person maintains by hand.

Mapped back onto the six rows: the first four, code review through an automated end-to-end check, are exactly the ones a codebase-derived agent can generate and keep current. The last two, an exploratory session and a beta with real users, stay untouched, because nothing about reading a codebase tells an agent what a person will judge as correct.

What Should Stay Human

Being honest about the boundary matters more than being impressive about the automation. Validation in its judgment sense, a beta program with real users, an exploratory pass where someone pokes at a feature because it feels off, stays human, and no tool that reads a codebase changes that. Load testing and accessibility testing are their own specialties with their own tools, and they answer questions about capacity and inclusivity that neither verification nor validation, as defined here, actually covers. Unit-level structural coverage and contract testing between services belong to a unit runner and a contract-testing framework, not to a tool built to drive a running application end to end. Recommending one vendor for all of that would be dishonest about what any single tool can do.

None of that is a knock on automation, and it isn't an excuse to skip it either. A team that automates nothing spends its scarce human judgment rewriting the same handful of checks every release instead of running a beta cohort past a feature that might not be right yet. A team that automates everything and calls the result "validated" has just relabeled a verification check and started trusting it for something it was never built to answer. The useful middle ground names both questions honestly and spends automation on the one that tolerates it.

The oracle problem, what a validation check compares against when there's no spec to compare against, is the part this article only touches at the surface: a validation oracle is a person's stated or demonstrated intent, and figuring out how to state that intent precisely enough to check against it is its own hard problem. The validation deep dive covers where that oracle comes from and how it gets stated. Acceptance testing and UAT sit inside validation for the same reason those checks compare against what a stakeholder wants, not against a written spec, which is why acceptance testing earns its own definition rather than folding into this one.

Where the oracle comes fromWhat decides pass or failCodeCheckCompareClosed loop, checks itselfSystem behaviorHumanjudgementNo loop back

One loop closes on its own. The other only closes when a person decides.

Verification and Validation Are Not a Vendor Category

A team debugging a checkout failure at 2 a.m. doesn't need a philosophical distinction; it needs to know whether the failure traces back to a spec the code violated or a user expectation nobody wrote down. The first is a bug a verification suite should have caught before merge. The second is a product decision no test suite, however well generated, was ever going to catch.

None of this is a "which tool" question, and treating it like one is how a comparison table ends up recommending a single product for problems that don't share an oracle. A tool that generates and runs verification checks against a running build, a contract-testing framework, a load-testing tool, an accessibility scanner, and a person running a beta program are five different answers to five different questions, and the right setup uses all five rather than picking one and hoping it covers the rest.

The smoke-testing gate is a useful reference point here: it's a verification activity through and through, a fast, shallow check that a build is alive enough to test further, and it says nothing about whether the build solves the user's problem. Right above smoke on that same ladder sits build verification testing: a longer checklist that decides whether a build is worth handing to QA at all, still checked against the build's own contract, so still verification. That's by design. A smoke gate that tried to answer validation's question would stop being fast, and a validation pass that tried to answer smoke's question would stop being thorough. Different questions, run at different points, for different reasons.

None of this makes the standard side-by-side comparison wrong exactly. It just answers a simpler question than the one most teams face today. The question that actually matters is which of the two your next automated check is answering, and once that's clear, deciding what still needs a person stops being a debate and becomes arithmetic. Connecting a repository to Autonoma is what turns the verification half of that arithmetic into something regenerated on every pull request, instead of a suite someone has to remember to keep honest.

Frequently Asked Questions

Verification checks a system against its own specification, using reviews, static checks, and tests derived from the code. Validation checks a system against what the user actually needed, using real behavior, a beta program, or an exploratory session, because there's no written spec to compare against. Verification asks whether it was built right; validation asks whether the right thing was built at all.

Verification. A unit test calls a function and checks the result against what that function was documented or designed to return. The oracle is the function's own contract, which lives inside the codebase, so the check never looks outside the system for its answer.

Validation. User acceptance testing checks a build against what a stakeholder or user actually wants, not against a written spec, which is the same reason acceptance testing gets treated as its own activity rather than folded into a spec-compliance check.

Under the older model, verification ran continuously and validation ran once, late, because running the real system in front of real behavior required a person to do it by hand. Once that stops being expensive, both can run together on every commit instead of taking turns, so 'which comes first' stops being the useful question.

Verification, mostly. Autonoma's agents read the codebase and generate end-to-end checks derived from what the code already does, then run those checks against a running build on every pull request. That is verification by this article's own definition: the oracle is the code itself. The validation half, a beta program, an exploratory pass, a person judging whether the feature was the right one to build, stays a human job that Autonoma does not replace.

Verification, in almost every case. An automated check is derived from something written down inside the system, a spec, a type contract, a documented return value, or the codebase itself, and it compares the build against that written source. Automation makes the verification half run faster and more often; it doesn't move an activity into validation, because nothing in a codebase records a person's judgment.

V&V is the standard shorthand for verification and validation treated as one paired process. IEEE 1012-2024, the active edition, defines V&V as determining whether a system's development products conform to the requirements of their own activity, and separately, whether the finished product satisfies its intended use and its users' needs.

Verification is performed by whoever or whatever can read the spec: a human reviewer at code review, a compiler or linter on a static type check, a test runner on unit tests, or an AI test agent on a generated end-to-end check. Validation is performed by people whose judgment is the oracle: a QA engineer running an exploratory session, or a product or support team watching real users in a beta. The performer varies; what the check compares against is what decides which question is being answered.

Related articles

A single lime-highlighted oracle panel beside a chain of automated procedure steps, representing the one part of validation testing that still requires human judgment

Validation Testing Runs at 3 Levels, Not One

Validation testing checks behavior against user intent, not code against spec. The three levels, the test oracle problem, and why judgment stays human.

A horizontal agent trajectory diagram showing a tool call passing a right-tool checkpoint but failing an argument-accuracy checkpoint

How to Test AI Agents That Take Actions (Tool Calls)

A runnable guide to testing tool-calling agents: right tool, right order, right arguments, mocked vs live calls, failure handling, and non-determinism.

A chatbot test pipeline moving from manual QA through scripted and semantic assertions into an automated CI gate that samples the model N times before allowing a merge

Chatbot Automation Testing: Why Assertions Fail

Chatbot automation testing that survives non-deterministic replies: the migration to a CI gate, n-run sampling, threshold gating, and real GitHub Actions YAML.

Sealed tenant data capsules being sorted into fully partitioned vault compartments, each isolated from the others, illustrating multi-tenant test data isolation

Multi-Tenant Test Data Isolation

What multi-tenant test data isolation means, why it matters for testing, and the four isolation patterns (schema, row-level, database, per-run) with tradeoffs.