User acceptance testing (UAT) is the last stage of testing before a release, where the people who will actually use the software try it on their everyday tasks and confirm it does what they need. Unit tests and QA check that the software works as specified. UAT checks that the specification was right. A round ends with a sign-off against criteria agreed at the start, and anything that doesn’t match what users expected, whether or not it’s technically a bug, gets logged, triaged and either fixed or deliberately deferred.
The most embarrassing bugs I’ve shipped all had one thing in common: the test suite was green. The code did exactly what the spec said. The spec just didn’t match what people actually needed. UAT exists for that gap.
Why I can’t test my own features#
By the time a feature is ready, I’ve walked its happy path a few hundred times. I know which button to press because I built the button. That familiarity makes me the worst possible test user, and it makes QA only half a solution, because QA still tests against the spec. UAT is the one stage where the question changes from “does it work as designed?” to “was it designed right?”
UAT, QA and beta testing aren’t the same thing#
People use these interchangeably, and it causes real confusion about who’s meant to be doing what.
| QA | UAT | Beta | |
|---|---|---|---|
| Question | Does it work as specified? | Does it work for the people who’ll use it? | How does it hold up in the wild? |
| Who | Testers, developers | Real or representative users, the business owner | A slice of real customers |
| Where | Test environment | Staging, with realistic data | Production |
| Finds | Defects against the spec | Gaps between the spec and real work | Scale, device and data surprises |
| Ends with | A pass on the test cases | A sign-off | A decision to roll out wider |
UAT sits between the other two. If QA is still finding crashes, it’s too early for UAT. Users will spend the whole round tripping over bugs and never get to the question you actually wanted answered.
Before the round starts#
Plan first: scope, timeline, who’s taking part, and what “pass” means. Vague success criteria are how UAT rounds drag on for weeks.
I also set entry criteria, which is a grand name for a short checklist. QA has passed with no open critical bugs. The staging environment has data that looks like the real thing, not “test test 123” accounts. The people taking part have time blocked out for it, not “whenever you get a chance”. That last one matters most. UAT squeezed in around someone’s real job gets about ten minutes of real attention.
Then pick people who resemble your real users. Colleagues who had nothing to do with the build work well; a small group of friendly external stakeholders who understand what the product is for works even better. Five to eight people is plenty for most features. Past that you mostly get the same feedback again.
Writing scenarios people can actually follow#
Write the scenarios around daily routines rather than edge cases. QA has already hammered the edges. A good UAT scenario reads like a normal Tuesday, not a stress test.
Each scenario has a goal and a starting point, and deliberately leaves out the steps. If you write “click New Invoice, then click Add Client”, you’re testing whether people can follow instructions, not whether the product makes sense. For an invoicing feature, a scenario might look like this:
Scenario 4: Bill a new client for part of a job
You’ve just finished the first half of a fit-out for a new client, Harbour Café. Invoice them for 50% of the agreed $12,000, due in 14 days, and send it to their accounts email.
Expected: the client gets an invoice for $6,000 with the right due date, and it shows as outstanding on your dashboard.
Ten to fifteen scenarios like that usually cover a feature. I sit in on the first couple of sessions, say as little as possible, and watch where people hesitate. A pause before a button tells you more than anything written in the feedback form.
Logging UAT feedback#
During the round, anything that doesn’t match what users expected gets logged, including things that are technically “working as intended”. If someone expected one thing and got another, that’s information whatever the spec says.
The log doesn’t need a special tool. A shared sheet or a dedicated board in whatever issue tracker you already use is enough, as long as every entry has the same few fields:
| Field | Example |
|---|---|
| Scenario | 4: Bill a new client for part of a job |
| What I expected | To enter 50% and have it work out the amount |
| What happened | Had to calculate $6,000 by hand; no percentage option |
| Severity (as the tester sees it) | Annoying, not blocking |
| Screenshot or recording | Attached |
“What I expected” is the field that does the work. Without it you get “the invoice screen is confusing”, which nobody can act on.
Triaging the feedback#
At the end of each day, or each round for a small one, I go through the log with the product owner and sort every item into one of four piles.
A bug is something broken, like a wrong total or an error page. It gets fixed before sign-off if it’s serious, otherwise scheduled.
A change request means it works as specified but the specification was wrong, as with the missing percentage option above. This is the feedback UAT exists to find, and the hardest to handle, because fixing it means more scope. The product owner decides: fix now, or accept and schedule it.
A copy or training issue means the feature is fine but people didn’t understand it. Often a label, a hint or one line in the help docs fixes it. Cheap, and worth doing.
Won’t fix covers out-of-scope ideas and one person’s preference against everyone else’s. Write down why, and tell the person who raised it. Testers who never hear back stop giving feedback in the next round.
The thing I try hardest to avoid is treating every item as a bug to be fixed before launch. That’s how a two-week round turns into two months. The goal of UAT feedback isn’t zero items. It’s that every item has a decision attached.
Sign-off#
Afterwards, fix what needs fixing, and if the changes were substantial, run another short round rather than assuming they landed well. Then get a real sign-off against the criteria you agreed at the start. That means a named person saying “yes, ship it”, with any deferred items listed alongside, not a thumbs-up emoji in a group chat.
Mistakes I’ve made running UAT#
Running it too late. If UAT starts two days before a fixed launch date, every change request becomes an argument about whether to delay, and the answer is always no. Leave room to act on what you find.
Testing with the wrong people. Internal staff who know the product too well behave like the developers did. They know where everything is.
Treating silence as approval. If a tester logs nothing, they probably didn’t really test. Check in before counting them as a pass.
And letting UAT become a checkbox at the end of a sprint. It’s better treated as the last gate: the final moment before launch where someone who isn’t you tries to use the thing.
What it buys you#
Mostly, it catches problems while they’re still cheap: before launch, instead of a patch and an apology after. There are quieter wins too. Training and support get easier, because the flows match how people actually work. And stakeholders who took part in the testing sign off faster, because by that point it’s partly their product. The releases I’ve seen get a proper UAT round tend to be the calm ones.
In short#
UAT is where real users check the software does what they need before it ships. Start it once QA is clean. Invite five to eight people who look like your users, write scenarios as everyday goals rather than steps, and log every gap between what they expected and what happened. Sort each piece of feedback into bug, change request, copy issue or won’t fix, make a decision on every one, and finish with a named sign-off.
