Guide · updated 22 September 2026
A UAT test plan template a non-technical tester can actually follow
Most test plans fail for the same reason: they were written for the person who built the app. Here is the shape that works for everyone else, with a template you can copy.
User acceptance testing is the pass a human makes over a real build before it ships. Not unit tests, not CI — somebody opens the app, signs up, and tries to use it like a customer would. The plan they work from decides whether that pass is thorough or theatre.
The columns that earn their place
Every row is one check. Six columns are enough, and each one exists for a reason:
- ID —
AUTH-01,PAY-02. A handle people can quote in a message. "The sign-in one is broken" starts an argument; "AUTH-02 fails on Android" does not. - Journey — what is being checked, in the words a customer would use. Not "validate auth endpoint".
- Preconditions — the state the tester must be in first. Signed in or out, a saved card, a specific account. Half of all "it doesn't work" reports come from skipping this.
- Steps — numbered, followable by somebody who has never seen the code. No file paths or endpoints.
- Expected result — concrete and checkable. Never "it works".
- Platform columns — one per platform you ship on, and
N/Awhere the feature genuinely does not exist there. A blank is "not tested yet"; N/A is "there is nothing to test".
Write expected results a tester can judge alone
The difference between a plan that finds bugs and one that does not is almost always the expected result. Put the judgement in the plan, not in the tester's head.
- Weak: "The error is handled."
- Strong: "A message says the email or password is wrong. The password field is cleared; the email is kept."
The second version catches a real bug — the field that keeps a wrong password — that the first version lets through, because the tester saw an error and ticked it.
Cover the unhappy paths
Teams test the path they demo and ship the rest untested. For each important journey, add rows for: no network, a declined payment, a permission denied, a session that expired, and the back button pressed halfway. These are where customers actually meet your app on a bad day.
The template
Copy this, replace the app's journeys with your own, and keep the structure. It is written in the format qarunbook imports, so a whole plan becomes a board in one paste.
# Rideshare app — release test plan ## Sign up and sign in (AUTH) | ID | Journey | Preconditions | Steps | Expected result | WEB | AND | IOS | |---|---|---|---|---|---|---|---| | AUTH-01 | Sign up with an email address | No account for this email | 1. Open the app. 2. Tap Create account. 3. Enter a name, email and password. 4. Submit. | The account is created and the app opens on the home screen. A verification email arrives within a minute. | | | | | AUTH-02 | Wrong password shows a clear error | An existing account | 1. Sign in with the right email and a wrong password. | A message says the email or password is wrong. The password field is cleared; the email is kept. | | | | | AUTH-03 | Reset a forgotten password | An existing account | 1. Tap Forgot password. 2. Enter the email. 3. Open the link in the email. 4. Set a new password. | The new password signs you in. The old one no longer works. | | | | | AUTH-04 | Sign out on one device only | Signed in on two devices | 1. Sign out on device A. | Device A returns to the sign-in screen. Device B stays signed in. | | | | ## Booking a ride (RIDE) | ID | Journey | Preconditions | Steps | Expected result | WEB | AND | IOS | |---|---|---|---|---|---|---|---| | RIDE-01 | Set pickup from current location | Location permission granted | 1. Open the app. 2. Tap Use my location. | The pickup pin lands on the street you are on, and the address matches. | | | | | RIDE-02 | See the fare before confirming | A pickup and destination set | 1. Enter a destination. 2. Wait for the estimate. | A fare and an arrival time are shown before any Confirm button. | | | | | RIDE-03 | Cancel within the free window | A booked ride, under 2 minutes old | 1. Open the ride. 2. Tap Cancel. | The ride is cancelled and no fee is charged. The screen says so. | | | | | RIDE-04 | Booking with no network | Aeroplane mode on | 1. Try to book a ride. | A message says there is no connection. Nothing is booked, and nothing is charged. | N/A | | | ## Payments (PAY) | ID | Journey | Preconditions | Steps | Expected result | WEB | AND | IOS | |---|---|---|---|---|---|---|---| | PAY-01 | Pay with a saved card | A saved card | 1. Finish a ride. 2. Pay with the saved card. | The payment succeeds and a receipt appears within a minute. | | | | | PAY-02 | Declined card is handled | A card that will decline | 1. Finish a ride. 2. Pay with the declining card. | A message says the card was declined and offers another method. The ride stays unpaid, not cancelled. | | | | | PAY-03 | Receipt matches the fare | A completed, paid ride | 1. Open the receipt. | The total matches what was shown at booking, including any surcharge, itemised. | | | | ## Notifications (PUSH) | ID | Journey | Preconditions | Steps | Expected result | WEB | AND | IOS | |---|---|---|---|---|---|---|---| | PUSH-01 | Driver-arriving alert | A booked ride, notifications allowed | 1. Wait for the driver to arrive. | A notification says the driver has arrived, and tapping it opens the ride. | N/A | | | | PUSH-02 | Notifications off is respected | Notifications denied | 1. Book a ride and wait. | No notification appears, and the app does not crash or nag on every screen. | N/A | | |
Or take the file: Markdown·CSV·Excel·no email, no sign-up.
How many checks is enough?
For a small app, 30 to 60 checks across the main journeys. For something larger, a few hundred. The useful test is not the count: it is whether finishing the list means the app has genuinely been exercised. If you can finish the plan and still be surprised by an obvious bug, the plan is missing a journey.
Then track what happens to each one
A plan in a spreadsheet goes stale the moment testing starts: results in one place, bugs in another, and no way to tell what has been checked since the last build. The plan needs to become a board where every check carries its result per platform, who recorded it, and whether a fix has been checked again.
That last part matters more than it sounds. When a bug is fixed, the check underneath it should not silently go back to passing — the person who passed it last was looking at a build without the fix in it.