User acceptance testing (UAT) is the last gate before release where the business side, not QA, decides whether a build does what a real user actually needed, not just what the ticket described. It runs against realistic end-to-end scenarios, gets signed off by a named business stakeholder or the actual end users, and sits inside validation rather than verification. Done well, it runs against clear entry and exit criteria and produces a written sign-off record. Done badly, it quietly becomes a second QA pass where nobody is really accepting anything.
A build clears every automated check on Tuesday. Someone still books a UAT session for Thursday, and nobody can say what happens if one of the six invitees says no. That's usually the moment a team discovers it never decided who owns UAT, or what gets signed at the end. The sign-off, if it exists, is a thumbs-up in a chat thread.
This is written for the engineer, SDET, or release owner deciding whether this build ships, or who was just told to name and run the UAT gate. It is not for the QA lead building a suite-allocation strategy, for someone asking whether an AI-generated suite is testing anything real, or for someone picking edge-case inputs for a single test case. This is the one about the session itself: who runs it, what it checks against, and what you hand someone to sign.
What UAT Testing Actually Is (And What It Is Not)
What UAT Actually Checks
UAT checks a build against what a business stakeholder or end user actually needed, using their own judgment as the standard, not a written spec. That's the same distinction verification and validation draws at the level of a single check: verification asks whether a build matches its own spec, something a reviewer or a test derived from the code can answer. Validation asks whether it matches what the user meant, and UAT is validation's most formal, most scheduled expression of that question. No artifact in the repository records what a stakeholder wanted well enough for a machine to compare against it. A person has to look at the running product and decide.
What UAT Is Not
UAT is not a second regression pass, not a bug hunt for edge cases, and not a rerun of whatever QA already checked under a different name. It's also not the same activity as alpha testing or beta testing, a distinction covered in full at alpha vs beta testing: alpha and beta widen the audience to surface problems nobody on the build team would try, while UAT narrows it to the people whose judgment the release depends on and ends in a decision, not a feedback stream. Acceptance testing maps the full family; UAT is the branch where the business decides go or no-go on a specific build before it ships.
This page is for deciding whether today's build clears this gate. Deciding what a QA org tests next quarter, or whether an AI-authored suite is trustworthy, are separate, adjacent decisions with their own answers elsewhere.
Who Owns UAT (And Who Actually Signs)
Ownership splits into two jobs that get conflated constantly: who writes the scenarios, and who signs off. Writing usually falls to product or the business. Signing has to fall to someone who holds the standard the build is checked against: a named business stakeholder, the actual end users, or an operations lead who'll live with the workflow.
The failure mode shows up constantly. Nobody outside QA has the time, so the ticket lands on a QA engineer's desk. They run through the scenarios they already tested and sign their own name at the bottom. That stops being acceptance testing the moment the person accepting the build already approved the spec it was built against, because the one thing UAT is supposed to catch, a build that's technically correct but wrong for the business, is invisible to them by construction.
Writing and signing are two different jobs. QA can support the middle step, never the ends.
The Difference Between UAT and QA Testing
QA testing checks a build against something written down: a spec, a ticket, a contract. User acceptance testing checks it against something never fully written down: what the business actually needed. QA runs continuously through development, performed by QA engineers and automation; UAT runs once, close to release, performed by the business against a build that already passed QA.
| Dimension | UAT | QA Testing |
|---|---|---|
| Checked against | Business need, real usage | Written spec or ticket |
| Performed by | Business or end users | QA engineers or automation |
| Timing | Late, close to release | Continuous, through development |
| A failure means | Wrong thing was built | Build misses its own spec |
| Who signs off | The named business owner | QA lead, as a merge gate |
The row worth sitting with is "a failure means." A QA failure is fixable by making the code match its contract. A UAT failure can happen on a build that's flawless against its own spec, because the spec asked for the wrong thing, and no amount of QA rigor fixes that. For what the QA side looks like once agents generate the checks, manual QA vs AI testing covers the shift.
UAT Entry and Exit Criteria
UAT testing without entry criteria starts on whatever build happened to be sitting in staging, and spends its first hour discovering the environment doesn't match production instead of judging the product. Concretely, a build should meet four conditions before anyone gets invited:
- Feature-complete against the accepted ticket, not a partial build with a promise to finish later.
- The environment matches production closely enough that timing and data behave the way they will after release.
- Known blocking defects are closed, not deferred with a note to "check in UAT."
- Test data is seeded ahead of time, not improvised mid-session while people wait.
Exit criteria decide when the build gets to leave, and they're just as often skipped:
- Every scenario has a recorded result, including the ones skipped as "obviously fine."
- Every criterion has a named signer, not just a status column that says pass.
- Any failure carries an explicit decision: fixed and retested, waived with a reason, or blocking.
- The sign-off record is filed somewhere the release depends on, not a chat thread.
The general mechanics live at test entry and exit criteria. This is the UAT-specific version.
Entry decides whether the session is worth running. Exit decides whether the build ships.
A Filled UAT Test Plan and Sign-Off Template
Most pages describe what a UAT plan should contain and stop short of showing one. Here is a filled version built around one scenario domain, a B2B subscription product's checkout and plan-change flow, so every row stays consistent. The nouns are the only thing you should need to change to reuse it.
| Scenario | Precondition | Test Steps | Expected Result | Owner |
|---|---|---|---|---|
| New customer signs up and pays | Valid card, no existing account | Create account, enter card, submit | Account active, invoice emailed | End user |
| Upgrade from Starter to Pro | Active subscription on Starter plan | Open billing, select Pro, confirm | Prorated charge shown, plan updated | End user |
| Downgrade from Pro to Starter | Active subscription on Pro plan | Open billing, select Starter, confirm | Downgrade scheduled, no charge yet | End user |
| Renewal with a declining card | Card on file set to decline | Trigger renewal, review dunning email | Access retained through grace period | Billing stakeholder |
| Cancel an active subscription | Active subscription, no pending invoice | Open billing, cancel, confirm | Access ends at period end | End user |
The plan tells whoever runs the session what to do and what "correct" looks like. It doesn't say what actually happened, or who's willing to put their name on it. That's a separate document, filled in during the session, with exactly the columns a sign-off needs.
| Scenario | Acceptance Criterion | Tester | Result | Sign-off |
|---|---|---|---|---|
| New signup and payment | Account active, invoice sent fast | M. Alvarez, Sales Ops | Pass | M. Alvarez, Aug 11 |
| Upgrade Starter to Pro | Proration shown, plan updates now | J. Okafor, Finance | Pass | J. Okafor, Aug 11 |
| Downgrade Pro to Starter | Downgrade scheduled, no charge yet | J. Okafor, Finance | Pass | J. Okafor, Aug 12 |
| Renewal with declining card | Access retained through grace period | R. Singh, Support Lead | Pass, with a note | R. Singh, Aug 12 |
| Cancel active subscription | Access ends at period end | M. Alvarez, Sales Ops | Fail, access revoked at once | Withheld, blocks release |
Row five is the point of the exercise, not an embarrassment to edit out. The build revoked access the moment cancellation was confirmed instead of at the end of the paid period, a real gap between what shipped and what the business had promised. Nothing about that violates the original ticket, since the ticket never specified the exact moment access should end. It's the kind of thing a person notices by using the product the way a customer would.
Coverage used to compete with judgment for the same hour. Now it doesn't have to.
How Autonoma covers user flows before UAT
UAT exists, as a scheduled session, because covering every real user flow end to end used to be too expensive to author by hand, so judgment about whether the product was right got outsourced to the same session that also had to catch whatever coverage gaps slipped through everywhere else. When flows can be generated and run continuously instead, UAT shrinks back to the part that was always genuinely human: does this match what the business meant.
Look back at the filled plan above. Four of its five rows, signup, upgrade, downgrade, renewal, are pure coverage questions: does the flow work the way the code says it should. Only the fifth, whether immediate access revocation matches what the business promised customers, is a judgment call nobody could answer by reading the codebase. Historically all five competed for the same hour in the same room, so the one row that needed a human got the same rushed attention as the four that didn't.
We built Autonoma to read a codebase the same way the table above assumes a flow should be tested: from the actual routes, components, and user flows that exist, not a script someone wrote once for last quarter's UI. Our agents generate end-to-end checks from that reading and run them against a live preview of the running application on every pull request, so a routine flow like a plan upgrade or a declining card gets covered continuously, well before anyone schedules a UAT session for it. The Diffs Agent re-reads what changed on every pull request and keeps that coverage current, instead of letting it drift the way a hand-maintained regression suite does. None of that is a speed or coverage number we're claiming. It's an architecture choice: read the code, verify against the running product, keep it current automatically, with verification layers at each step.
Mapped onto the plan: the first four rows are exactly the kind of flow an agent can read from the codebase and verify continuously, before the build reaches a stakeholder's screen. The fifth is not, because nothing about reading a codebase tells an agent what a business promised its customers. That call still needs a person, and connecting a repository to Autonoma doesn't make it for them. What changes is how much of the session's time goes to coverage a machine can already show you, versus the one call only a person in the room can make.
None of this replaces the session itself. Autonoma doesn't sit in that room, doesn't decide whether a feature was the right one to build, and never signs anything. The judgment half stays exactly where it always belonged.
Common UAT Failure Modes
Vague acceptance criteria cause more UAT failures than bugs do. "Looks good" isn't a criterion two people can check the same way, and a session built on statements like it produces a sign-off meaning whatever the signer felt that afternoon. A criterion worth signing states the exact expected result, the way the sign-off template above does.
Sign-off theater is the softer version of the QA-takeover mode described earlier: everyone clicks through the happy path once and checks the box, without trying the scenario a real customer would hit sideways. The session happened. Acceptance didn't. A stale environment compounds it, since a build behaving differently in UAT than in production makes even a careful signer approve something never actually tested.
The quietest failure mode is the one where the ship decision already happened informally, in a hallway conversation or a chat thread, and UAT gets scheduled afterward as a formality nobody expects to change. A session that can't actually block release isn't a gate. It's a calendar entry.
A fifth mode is subtler: criteria written after the session instead of before it. Someone runs through the build, decides it's fine, and then reverse-engineers an acceptance criterion that matches whatever they happened to click on. That produces a signed document that looks identical to a real one, right up until the next release, when nobody can say what the previous sign-off actually promised.
How the Session Changes When Coverage Isn't the Bottleneck
Once the routine flows are already verified going in, the session gets shorter and sharper. Fewer scenarios need to run live, because most were already proven on the last several pull requests, not discovered for the first time in the room. The people in that room spend their hour on the handful of scenarios that actually need a human call, the same way a smoke gate decides whether the rest of a suite is worth running rather than catching every defect itself.
Signing off starts to mean reviewing a decision that's already mostly made, instead of discovering from scratch whether the product works. That's not a lower bar. It's a sharper one, because the only thing left to sign is the part that was always going to need someone's judgment, the way row five of the sign-off template above was never going to be caught by anything except a person using the product the way a customer would.
The bar the session used to fill on its own now splits: most of it runs on every commit.
None of this makes the UAT session skippable, and nobody should read a testing vendor telling you otherwise. The judgment call, whether this build actually does what the business meant, still needs a person willing to say yes or no and put their name on it. What's worth changing is what that person spends their hour on. Connecting a repository to Autonoma is what keeps the routine flows in a plan like the one above verified going into the session, so the only thing left on the table Thursday is the row that was always going to need a human anyway.
Frequently Asked Questions
User acceptance testing is the stage where a business stakeholder or the actual end users check a finished build against what they needed, not against a written spec. It uses their own judgment as the pass or fail standard, and it typically ends with a named person signing off that the build is acceptable to ship.
Business stakeholders, product owners, or the actual end users are responsible for UAT, both for writing the scenarios that matter to them and for signing off at the end. QA can help draft the logistics or set up test data, but the moment QA writes every scenario and signs off itself, the session has stopped being acceptance testing and become a second QA pass.
QA testing checks a build against a written specification, using QA engineers or automated checks as the judge. UAT checks a build against what the business or end user actually needed, using their own judgment as the standard, because that need was never fully captured in the spec to begin with. QA runs continuously through development; UAT typically runs once, close to release, against a build that has already passed QA.
Start from the real scenarios a user or stakeholder will actually run, not the ones that are easiest to script, and write each one with a precondition, the steps to run it, and an expected result stated concretely enough that two different people would agree on whether it happened. The filled test plan and sign-off template above are built from exactly that structure and can be adapted directly by swapping in your own scenario domain.
Entry criteria are the conditions a build must meet before a UAT session starts, such as being feature-complete, running in a production-like environment, and having test data ready. Exit criteria are the conditions that let a build leave UAT, such as every scenario having a recorded result and a named sign-off, and every failure having an explicit decision attached rather than being silently ignored.
Autonoma makes UAT sessions sharper by getting the routine flows verified before anyone schedules one. Its agents read your codebase and generate end-to-end checks that run the flows a codebase already describes against a live preview on every pull request, so those flows arrive at UAT already proven. That frees the session to spend its time on the judgment call a codebase can't answer, whether the build matches what the business actually meant, which is the part of UAT that was always meant to stay human. Autonoma handles the coverage going in; the sign-off stays yours.




