tldr: Acceptance testing is the final check that a build meets business requirements before it ships. Done right, it catches misalignment between what was built and what was asked for. Done wrong, it becomes a bureaucratic gate that ships nothing useful.
What acceptance testing is for
Acceptance testing answers one question: does this work for the people who will actually use it?
Unit tests prove your code does what you intended. Integration tests prove components fit together. Acceptance testing proves you intended the right thing.
The distinction matters because most production incidents are not from incorrect code. They are from correct code solving the wrong problem.
Types of acceptance testing
There are four common forms, and most teams need at least two of them.
User acceptance testing (UAT) runs the build against real users or business stakeholders. Are the workflows usable? Does the output match what the business needs? See UAT testing for the deeper guide.
Business acceptance testing (BAT) verifies the build delivers the business value originally requested. Often run by product managers or business analysts.
Contract acceptance testing (CAT) verifies the build meets contractual obligations to a customer. Common in B2B software, government work, and regulated industries.
Operational acceptance testing (OAT) verifies the build can be operated, monitored, and maintained in production. Backups work. Logs are useful. Runbooks match reality.
Most internal SaaS products only need UAT and BAT. Regulated software usually needs all four.
Who runs acceptance testing
Not QA. That is the most common mistake.
QA writes the test plan, owns the environment, and supports the process. The tests themselves should be executed by the audience the build is meant to serve. End users for UAT. Product or business owners for BAT. Customer representatives for CAT. Operations or SRE for OAT.
When QA runs acceptance tests on the user's behalf, you get tests that pass against the spec but miss what users actually do.
How to write useful acceptance criteria
Bad acceptance criteria look like "the system should be user-friendly." Good criteria are specific, observable, and binary.
A working pattern is Given / When / Then:
Given a logged-in customer with at least one saved card
When they click "Buy Now" on a product page
Then the order is placed using the saved card without any payment screen
That criterion has one outcome you can verify. There is no ambiguity. A test either passes it or fails it.
Each acceptance test should map to a real user goal, not a feature. "Verify checkout works" is a feature. "A returning customer can complete a one-click purchase in under 30 seconds" is a goal.
Where teams get stuck
Three patterns cause acceptance testing to fail:
- The QA team runs UAT. Already covered. Stop doing this.
- Acceptance tests are written after the code. They become a rubber-stamp, not a check. Acceptance criteria belong in the user story before development starts.
- No one updates the criteria. Requirements change during development. If the criteria do not change with them, the test passes against an outdated spec.
A simple fix: every story moves through "in review" only after both the code and the acceptance criteria have been updated together.
Automating acceptance tests
Most acceptance tests run by humans because the criteria involve subjective judgment. But the deterministic ones, can the user complete the flow, are the form fields correct, does the receipt PDF look right, can be automated.
Cucumber and SpecFlow translate Given/When/Then directly into runnable tests. Modern AI testing tools take this further: instead of writing selectors and steps, you write the goal in plain English and the agent figures out the rest.
Bug0 and the open-source engine behind it, Passmark, let you encode acceptance criteria as natural-language tests. The agent navigates the app, validates the outcome, and reports specifically why a flow failed. That removes the maintenance tax that makes most acceptance test suites rot.
When acceptance testing is "done"
A useful exit criterion is a sign-off ratio: percentage of acceptance tests passed by the actual stakeholder, not the QA team.
Anything below 90% means the build is not ready. Above 95% with all critical paths passing usually means you are good to ship.
Time-based exits ("we tested for two weeks") are not acceptance testing. They are time-boxed prayer.
FAQs
What is the difference between acceptance testing and system testing?
System testing verifies the integrated software meets the technical specification. Acceptance testing verifies it meets the business need. Same build, different audience, different success criteria.
How is UAT different from QA testing?
QA testing checks if the build works as the team intended to build it. UAT checks if what was built solves the user's problem. Different question, different signal.
Should acceptance tests be automated?
Automate the deterministic parts: navigation, form submission, contract validation. Keep judgment calls (is this layout intuitive, does this copy match our voice) human. Most teams over-automate acceptance and end up testing against the same flawed assumptions as the code.
What happens if acceptance testing fails?
The build does not ship. Fix the gap, re-run the failed criteria. If you cannot fix it before deadline, scope down: ship the parts that passed and defer the rest.
How does Bug0 help with acceptance testing?
As a done-for-you QA service, Bug0 runs your acceptance flows continuously, in plain English, and reports failures with full reproduction context. It handles the regression load that makes manual acceptance testing impractical at scale.
