1. Home
  2. Blog
  3. Software Testing

Software Testing

User Acceptance Testing (UAT): Process, Checklist and Real Examples

Software can pass every test and still fail the people who need it. UAT is the final check that it solves the real business problem. Learn who should run it, how to plan it and when to sign off.

9 min read
User acceptance testing (UAT): process, checklist and real examples

Key takeaways

  • User acceptance testing checks that software meets real business needs, using real scenarios.
  • It is run by business users or customers, not by the team that built the software.
  • QA asks “does it work as specified?”, while UAT asks “does it solve the problem?”.
  • Agree on entry criteria, exit criteria and who signs off before UAT starts.

A team once delivers an expense system that passes every technical test. On the first day, the finance team discovers that it cannot handle multi-currency claims, which make up a large share of their work. Nothing was “broken”, but it was not usable. User acceptance testing exists to catch exactly that kind of gap before launch.

This guide covers how UAT differs from other testing, how to run it step by step, and how to decide when you are ready to release. The scenario above and the examples below are illustrative, and the process should be scaled to suit your project.

What is UAT?

UAT is usually the final testing phase before release, where the intended users confirm that the software can do their job in realistic conditions. It is also called end-user testing or acceptance testing. It comes after development and system testing, when the product is expected to be stable.

Its purpose is not to find every bug. By this stage, most of those should already be gone. The aim is validation: did we build the right thing? Testers verify that the product matches the specification. UAT validates that the specification, and the product, actually meet the need.

UAT vs QA testing

Aspect QA or system testing UAT
Main question Does it work as specified? Does it meet the business need?
Performed by Testers and QA engineers Business users or customers
Timing During and after development Just before release
Based on Requirements and designs Real business workflows
Focus Defects, edge cases, integrations Usability and fit for purpose
Technical knowledge Often high Not needed
Outcome Bug reports Acceptance or rejection

UAT does not replace other testing. If users keep hitting basic bugs, the build was not ready, and you are wasting their limited time. Those issues belong in earlier test levels and regression testing.

Who runs UAT?

Role Responsibility
End users Run scenarios and give feedback
Product owner or business analyst Defines scope, and writes or reviews scenarios
UAT coordinator or QA lead Plans the sessions, supports testers, tracks issues
Developers Fix issues and answer technical questions
Business sponsor Makes the final sign-off decision

Choose testers who really do the work today. An experienced claims handler will spot problems that a manager or a proxy never would. Include a range of experience, because a new employee often reveals confusing steps that an expert works around without noticing. And make sure that their managers free up time for this, as UAT cannot succeed on top of a full workload.

Types of UAT

Type What it checks Example
Business acceptance Meets business goals Staff complete a real claim from start to finish
Alpha testing Internal testing in a controlled setting Staff try a new app before external users
Beta testing Real customers in real conditions A limited public preview
Contract acceptance Meets agreed contract terms A client verifies a delivered system
Regulatory acceptance Meets legal or compliance rules Checks for healthcare or banking rules
Operational acceptance Ready to run in production Backups, monitoring and support processes

The seven-step UAT process

1. Define scope and goals

Decide what is being accepted, what is out of scope, and what business outcomes matter. For example: “Finance staff can submit, approve and pay an expense claim, in any supported currency.”

2. Agree on acceptance criteria

Write down in plain language what success looks like, ideally at the start of the project rather than the week before launch. Vague criteria lead to arguments later on.

3. Choose and brief testers

Select real users, explain the purpose, show them how to record feedback, and make clear that they are testing the software rather than being tested themselves. Many people worry about getting something wrong.

4. Prepare the environment and data

The UAT environment should resemble production as closely as is practical. Use realistic data, set up the correct user roles, and check integrations such as email. If you copy production data, mask personal information first. Run a quick smoke test, so that testers do not arrive to find a broken build.

5. Write scenarios

Base these on real workflows rather than individual buttons. They should read like the job, not like the software. Our guide to test case vs test scenario explains how much detail you need.

6. Run the tests and collect feedback

Run sessions with someone available to help. Collect issues in one place, with screenshots. Leave some time for free exploration too, since people try things that scripts never anticipate. Exploratory testing offers useful techniques for this.

7. Fix, retest and sign off

Triage the feedback, fix what matters, and have the same users confirm the fixes. Then record a formal decision.

A UAT test case

A UAT test case should be easy for someone non-technical to follow. Here is an example for an expense system:

ID:        UAT-012
Scenario:  Submit a foreign currency expense claim
User role: Sales employee
Before:    Logged in, with a USD receipt ready

Steps:
  1. Create a new expense claim
  2. Enter a client dinner of 80 USD and attach the receipt
  3. Submit the claim for approval

Expected:  The amount is converted to INR at the current rate
           The manager receives an approval request
           The claim shows as "Awaiting approval"

Result:    Pass / Fail
Comments:
Tester / Date:

Note that it describes a real task, not technical details, and that it leaves room for comments. Those comments frequently turn out to be the most valuable part, such as “this works, but I would never find that button”.

Tip: Watch at least one user do this in person or on a call. People often work around confusing software and never report it. Seeing them hesitate tells you more than a “Pass” ever will.

Entry and exit criteria

Entry criteria (ready to begin) Exit criteria (ready to finish)
System testing is complete All critical scenarios have been run
No open critical or high bugs No open critical bugs
Environment and data are ready Agreed pass rate has been reached
Scenarios are reviewed Remaining issues have an agreed plan
Testers are briefed and available Business sponsor has signed off

These fit into the wider software testing life cycle. Set the numbers with your stakeholders in advance. “We will decide when it feels right” tends to lead to a rushed yes, driven by the deadline.

Handling feedback

UAT feedback is a mixture of things, and not all of it is a bug. Sort it into categories:

Type Example Usual action
Defect The total is calculated wrongly Fix, based on severity
Missed requirement Multi-currency is not supported Fix before launch, or re-plan
Usability issue Users cannot find the submit button Often worth fixing
Change request “Could it also export to PDF?” Add to the backlog
Training issue The feature works, but was misunderstood Update guides

Use clear rules for what blocks a release, as described in severity vs priority. And respond to every item, including the ones you decline. People stop giving feedback if it seems to disappear. Our guide on how to write a bug report may help testers describe issues clearly.

UAT checklist

Before UAT

  • Scope and acceptance criteria are agreed in writing
  • System and regression testing are finished
  • Testers are chosen, briefed and given time
  • Environment, accounts and realistic data are ready
  • Personal data in copies has been masked
  • Scenarios are reviewed by the business
  • One place to record issues is set up
  • Sign-off owner is named

During UAT

  • A support contact is available
  • Issues are triaged every day
  • Progress is shared with stakeholders
  • Fixes are deployed and retested in a controlled way

After UAT

  • Exit criteria have been checked
  • Known issues are documented, with owners
  • Formal sign-off is recorded
  • Training and release notes are updated
  • A short retrospective has been held

UAT in Agile teams

Traditional UAT comes as one large phase at the end, where a surprise is expensive. Agile teams shorten that loop. Product owners review each story against its acceptance criteria during the sprint, and users see working software at sprint reviews. Many teams still run a focused UAT before a major release, particularly where several features combine into one workflow.

With frequent releases, techniques such as feature flags and canary deployments let real users try new work gradually. Note that these complement acceptance testing, but they do not automatically replace it, especially in regulated industries that need a formal record.

Common mistakes

  • Treating it as a formality. A sign-off with no real use protects nobody.
  • Using the wrong testers. Developers and QA have too much knowledge of the system to represent users.
  • Starting with an unstable build. Testers lose trust and interest quickly.
  • Leaving it until the last minute. There is then no time to fix what you learn.
  • Using unrealistic data. Test data rarely has the messy cases that real work does.
  • Letting scope grow. Treat new ideas as change requests, unless they are true blockers.

Final thoughts

UAT is your last chance to learn, before release, whether the software really helps the people who will use it. Plan it from the start of a project, recruit real users, and agree on what success looks like. For your next release, try one simple change: sit with one user during a real scenario, and say nothing while they work.

Frequently asked questions

What is user acceptance testing in simple words?

It is the final check where real users try the software with realistic tasks to confirm it meets their needs, before it is released.

Who is responsible for UAT?

Business users or customers run the tests. A product owner or QA lead usually coordinates, and a business sponsor typically makes the final sign-off decision.

What is the difference between UAT and system testing?

System testing checks that the software works as specified, and is done by testers. UAT checks that it meets business needs, and is done by users.

When does UAT happen?

Usually after system testing and before production release, once the software is stable. Agile teams may also run smaller acceptance checks in each sprint.

Can UAT be automated?

Parts of it, such as repeated checks of business workflows. However, judging whether software is useful and fit for purpose still needs real people.

Keep learning

Work with Stack Quora

Need help with testing, WordPress or SEO?

We help teams ship better software and grow their sites. Tell us what you are working on and we will suggest a clear next step.

Keep reading

More guides on testing, AI & modern development

Enjoyed this article? Pick a topic and jump straight into our newest tutorials.

Artificial Intelligence

LLM Structured Output Explained: Getting Reliable JSON From AI Models

LLM structured output explained with validation we ran in Pydantic: JSON mode and schemas, constrained decoding, the ways model output…

Read article →
DevOps

SSH Keys Explained: How They Work, ssh-keygen, Ed25519 and Safe Habits

SSH keys explained with keys we generated: public vs private keys, ssh-keygen, Ed25519 vs RSA, fingerprints, passphrases, ssh-agent, authorized_keys, config…

Read article →
DevOps

HTTP Caching Explained: Cache-Control, ETag and 304 Responses, With a Live Test

HTTP caching explained with a small server we ran: Cache-Control directives, max-age, no-cache vs no-store, ETag revalidation and 304 responses,…

Read article →
Test Automation

API Contract Testing Explained: Catch Breaking Changes Before They Ship

API contract testing explained with a schema check we ran: what a contract is, consumer-driven contracts, Pact, OpenAPI, which changes…

Read article →
Software Testing

Risk-Based Testing Explained: Score Risks, Build a Matrix and Test What Matters

Risk-based testing explained step by step: identifying risks, scoring likelihood and impact, building a risk matrix, mapping risk to test…

Read article →
Databases & SQL

SQL Constraints Explained: NOT NULL, UNIQUE, CHECK and FOREIGN KEY, Tested

SQL constraints explained with tests we ran: NOT NULL, UNIQUE, CHECK, DEFAULT, PRIMARY and FOREIGN KEY, the NULL loopholes, SQLite's…

Read article →
Databases & SQL

SQL Date Functions Explained: Adding, Comparing and Grouping Dates Without Bugs

SQL date functions explained with queries we ran: adding intervals, month-end surprises, date differences, the BETWEEN trap, grouping by day,…

Read article →
Software Development

Python asyncio Explained: async, await, gather and TaskGroup With Real Timings

Python asyncio explained with code we timed: coroutines, await, gather, TaskGroup, error handling, timeouts, limiting concurrency and the blocking-call mistake…

Read article →
Software Development

Debounce vs Throttle in JavaScript: How They Work, When to Use Each, Tested

Debounce vs throttle in JavaScript explained with timings we measured in Node.js: how each works, simple implementations, leading and trailing…

Read article →
Software Development

Python Context Managers Explained: The with Statement, contextlib and Real Uses

Python context managers explained with code we ran: how with works, __enter__ and __exit__, contextlib.contextmanager, suppress, ExitStack, database transactions and…

Read article →
Artificial Intelligence

LLM Temperature and Top-p Explained: How AI Models Choose Their Next Word

LLM temperature and top-p explained with a simulation we ran: how probabilities are reshaped, what top-p keeps, recommended settings by…

Read article →
DevOps

YAML Explained: Syntax, the Norway Problem and Other Traps We Tested

YAML explained with a parser test: basic syntax, lists and maps, the Norway problem, versions turning into floats, octal zip…

Read article →
DevOps

Cron Jobs Explained: Syntax, Real Schedules and the Mistakes That Break Them

Cron jobs explained with schedules we verified: the five fields, operators, real examples, the day-of-month OR day-of-week trap, environment problems,…

Read article →
Software Testing

Bug Life Cycle in Software Testing: Every Status, Who Owns It and Common Mistakes

The bug life cycle explained: every defect status from New to Closed, who owns each step, rejected, deferred and reopened…

Read article →
Test Automation

Property-Based Testing in Python: Hypothesis Finds the Bugs Your Examples Miss

Property-based testing explained with Hypothesis tests we ran: properties vs examples, strategies, shrinking, the real bugs it found in our…

Read article →
Databases & SQL

SQL Pagination Explained: OFFSET vs Keyset, With a Million-Row Test

SQL pagination explained with a million-row test we ran: LIMIT and OFFSET, why deep pages get slow, keyset (cursor) pagination,…

Read article →
Databases & SQL

SQL EXISTS vs IN: Differences, the NOT IN NULL Trap and Performance

SQL EXISTS vs IN explained with queries we ran: how each works, why NOT IN returns no rows when a…

Read article →
Software Development

Python Logging Explained: Levels, Handlers, Formatters and Mistakes to Avoid

Python logging explained with code we ran: levels, basicConfig quirks, named loggers, handlers and formatters, logger.exception, lazy formatting, duplicate logs…

Read article →
Software Development

JavaScript Map vs Object: Key Differences, Pitfalls and a Benchmark

JavaScript Map vs Object explained with code we ran in Node.js: key types, ordering, the prototype trap, JSON, size, WeakMap…

Read article →
Software Development

Python Type Hints Explained: Annotations, mypy and the Errors It Catches

Python type hints explained with a real mypy run: basic annotations, Optional and unions, TypedDict, Literal, Protocol, generics, Callable, strict…

Read article →
Artificial Intelligence

LLM Tokens Explained: How AI Models Read Text, Count Costs and Fill Context Windows

LLM tokens explained with a tokenizer we ran: how text is split, why counts differ by language and tokenizer, context…

Read article →
DevOps

Semantic Versioning Explained: MAJOR.MINOR.PATCH, Ranges and Release Rules

Semantic versioning explained with code we ran: MAJOR.MINOR.PATCH rules, pre-releases, correct version sorting, caret and tilde ranges, 0.x versions, lockfiles…

Read article →
DevOps

Git Reset vs Revert: How to Undo Commits Safely, With a Tested Example

Git reset vs revert explained with a repository we built: soft, mixed and hard reset, revert commits, reverting merges, recovering…

Read article →
Software Testing

The Test Pyramid Explained: Layers, Ratios and When to Break the Shape

The test pyramid explained: unit, integration and end-to-end layers, sensible ratios, the ice cream cone anti-pattern, the testing trophy and…

Read article →
Test Automation

pytest Fixtures Explained: Scope, yield Teardown, conftest.py and Factories

pytest fixtures explained with a suite we ran: how fixtures work, scopes, yield teardown, conftest.py, factory fixtures, parametrized fixtures, built-ins…

Read article →
Databases & SQL

SQL Upsert Explained: INSERT ON CONFLICT, MERGE and the REPLACE Trap

SQL upsert explained with queries we ran: INSERT ON CONFLICT DO UPDATE and DO NOTHING, the excluded row, conditional updates,…

Read article →
Databases & SQL

SQL LIKE Operator Explained: Wildcards, Case Sensitivity and Performance

The SQL LIKE operator explained with queries we ran: % and _ wildcards, escaping, NOT LIKE and NULL, case sensitivity…

Read article →
Artificial Intelligence

AI Hallucinations Explained: Why Language Models Make Things Up and How to Reduce It

AI hallucinations explained: what they are, why language models produce them, common types, how to reduce them with grounding and…

Read article →
Test Automation

Mocking in Python: unittest.mock, patch and the Mistakes That Make Tests Lie

Mocking in Python with unittest.mock, tested: Mock and return_value, side_effect, patching where a name is used, spec and autospec, mocking…

Read article →
Software Testing

Code Coverage Explained: Line vs Branch Coverage and What 100% Really Means

Code coverage explained with a real coverage.py run: line, branch and condition coverage, reading a report, why 100% coverage can…

Read article →
Artificial Intelligence

What Are AI Agents? How They Work, With a Simple Agent Loop You Can Run

What are AI agents? A plain guide to the agent loop, tools, memory and guardrails, with a small Python loop…

Read article →
Test Automation

TDD vs BDD: Key Differences, One Feature Built Both Ways and When to Use Each

TDD vs BDD explained with one discount feature built both ways: red-green-refactor with code we ran, Given-When-Then scenarios, tools, trade-offs…

Read article →
Software Testing

User Acceptance Testing (UAT): Process, Checklist and Real Examples

User acceptance testing explained: who runs it, how it differs from QA, a seven-step process, a UAT test case template,…

Read article →
Artificial Intelligence

What Are Embeddings? Vectors and Cosine Similarity Explained Simply

What are embeddings? A plain-language guide to vectors, cosine similarity and semantic search, with a small example we ran, common…

Read article →
Test Automation

Flaky Tests: What Causes Them and How to Fix Them for Good

Flaky tests explained with demos we ran: the main causes, how to confirm and diagnose one, proper fixes for timing,…

Read article →
Software Testing

Load Testing vs Stress Testing: Differences, Metrics and k6 Examples

Load testing vs stress testing explained: what each proves, spike and soak tests, the metrics that matter, why averages mislead,…

Read article →