Acceptance criteria
Introduction#
Acceptance criteria (ACs) are clear statements that define what “working” means for a single backlog item. They are agreed before implementation starts and are what we test against, and prevent open-ended scope creep during implementation, as the target state is already agreed and documented.
They are one item on the team’s definition of done.
ACs are the bridge between the user need and the tests. A user story in “As a…/I can…/so that…” form is deliberately short and exists to start a conversation. The ACs are what that conversation produces: a clear description that a tester, a developer, and a Product Owner agree defines and delineates this backlog item.
This page covers the given, when, then format, what makes an AC good, what ACs are not, non-functional ACs, who writes them and when, the relationship with slicing, and how ACs generate tests.
Format#
Each AC describes one behaviour in the format “given, when, then.” The three parts are each important:
- Given describes the starting situation: the state of the system before action is taken.
- When describes the action or event that triggers something to happen: often a user action but could be a system-generated event.
- Then describes the observable outcome: what is different afterwards, and how this is visible.
Example AC
Given I am a new customer,
when I choose the register option,
then I am navigated to the user registration page.
An AC should be readable in one breath. If it needs a paragraph, the behaviour is either too large or not yet understood well enough.
Any part can be extended with and where one clause is not enough, although an AC needing several ands in its then should usually be split into several individual ACs.
The form is useful because it sharpens our thinking. Looser criteria such as “user can save a delivery address” leave out both the starting state and the observable result, which can lead to people making different assumptions. Writing given makes the context explicit, and writing then makes us explain what visibly changes, which encourages vertical slicing and makes the AC testable.
But the form is a means to an end. A simple statement that is genuinely testable beats a contorted given, when, then that satisfies the template while obscuring the point. In some cases, the situation is clear and there is no real action, so the given, when, then format can become cumbersome. For example, “postcodes are displayed in upper case with a single space before the final three characters” is cleaner than “given I have saved some addresses, when I am viewing my address list, then the postcodes are displayed in upper case with a single space before the final three characters.”
Worked example: an alternative delivery address
Each part of the AC is often written on its own line for readability.
Taking the item used throughout definition of done:
As an existing customer,
I can add an alternative delivery address,
so that I can easily choose which address to have my delivery sent to without needing to re-enter it every time.
Rough ACs for it might be:
Given I am signed in and have no alternative delivery address saved,
when I save an address with all required fields completed,
then it appears in my address book and is available to select at checkout.Given I am saving an alternative delivery address,
when the postcode is not in a valid UK format,
then the address is not saved
and the postcode field tells me what is wrong.
The discussion may identify adjacent ACs that best belong in separate user stories rather than expanding the original story:
Given I have an alternative delivery address saved,
when I place an order and select that address for delivery,
then the order is delivered to it
and my billing address is unchanged.Given I have placed an order to an alternative delivery address,
when I delete that address from my address book,
then it no longer appears at checkout
and the placed order still shows the address it was sent to.
It is also worth recording what this slice does not do:
Out of scope:
- More than one delivery address per order.
- Editing an address after an order has been placed.
- Any limit on the number of saved addresses.
The Ready stage example shows the same item taken further, with the postcode lookup behaviour, a non-functional AC, and the technical and test approaches attached.
What makes an AC good#
Observable. Somebody who knows nothing about how the system is built could look for the outcome and verify whether it has been met. “The order is delivered to the selected address” is observable. “The address service is called with the correct identifier” is not, because only a developer with a debugger or access to logs can see it. See also: Feature slicing.
Testable before the code exists. If we cannot describe the test before implementation starts, the AC is not yet clear enough. This is a very useful check to apply, and it is why the test perspective belongs in the conversation that produces the ACs rather than downstream of it.
Defines behaviour, not implementation. It describes a user-visible outcome, not which class, endpoint, or component makes it happen. Implementation guidance is useful information but should be clearly identified as such rather than disguised as acceptance criteria.
Describes one behaviour. When an AC fails, we want it to point at exactly one thing. An AC joining three separate outcomes with and is harder to translate into the tests that will verify it.
Written in the user’s language. Using technical or internal terms distracts from user needs and makes it harder for non-technical stakeholders to critique ACs.
ACs that do not work, and how to fix them
-
Vague: “The address form works correctly.”
“Correctly” is too open to interpretation, and nothing here is observable so no test can be written from it. Replace it with the specific behaviours that make up “correctly”, usually three or four ACs. -
Implementation detail: “Add a
delivery_addressestable with a foreign key tocustomers.”
This may be the right decision, but it does not describe user-visible behaviour and belongs in the implementation notes. If the team later stores addresses another way, this statement becomes false while the behaviour the user cares about is unchanged. -
Activity rather than outcome: “Validation is added to the postcode field.”
This describes work performed rather than behaviour observed. This could be better expressed as “Given I have entered a postcode, when it does not meet the expected format, then an error message is displayed.” -
Non-specific: “Saving an address is fast.”
Fast for whom, with how much data, on what connection? Better: “Given I have 200 saved addresses, when I save a new one, then it appears in my address book within one second.”
What ACs are not#
Not the technical approach. How we intend to build it is worth recording, and important technical decisions should be captured on the item so the reasoning is available to whoever will implement it. But they should be kept separate from the ACs, because they are not what the item will be tested against.
Not the UX/UI design. Link or attach the design rather than describing pixel positions and colours in prose. Equally, do not rely on the design to carry the behaviour. It can indicate what the empty state looks like or that a field is optional, but these need to be written down explicitly to avoid confusion. The design shows what it looks like, and the ACs say what it does.
Not the definition of done. Anything true of every item, such as tests written, peer review issues fixed, and static analysis clean, lives in the team’s definition of done for the implementation stage. Copying it onto every story makes the list long and buries the ACs that matter.
Not set in stone. They are the best shared understanding available at the time. We aim to decide ACs shortly before when the item will be implemented so we have the freshest information, but even so, the act of building sometimes reveals something missed or simply wrong. If this happens, we default to creating a new backlog item for the missed ACs rather than bloating the existing item.
Non-functional ACs#
Performance, capacity, security, accessibility, and resilience expectations are user-visible. A page taking ten seconds to load creates a poor user experience, however comprehensively it satisfies the functional ACs. These expectations, often called non-functional requirements or NFRs, therefore belong on the story that introduces the behaviour, expressed as ACs.
Why?
- These are user and business needs, not technical needs. A response time target exists because a user cannot wait, not because engineers like fast software. Cost to serve is the same: a limit on calls to a chargeable third party service is a business need with a number attached.
- They change how the thing is built. Discovering a 500ms expectation after the query has been written and the schema settled is expensive. Discovering it during refinement is free.
- Requirements defined elsewhere are easy to forget. Aim to include non-functional ACs in the item that implements the feature. However, in some cases, a basic first implementation is a valid early slice that may be followed by optimisations such as introducing paging. But in every case, NFRs should be treated as user or business needs. A separate NFR document which is rarely looked at tends to be ignored. Splitting non-functional needs into separate enabler items risks the feature being implemented in a way that makes them hard to meet or can lead to over-engineering due to the disconnect with user needs.
- Quantifying the need surfaces possible trade-offs. “Must be fast” cannot be negotiated or costed. “Interactive within 500ms with 100,000 records” can be, and can be knowingly relaxed if that is the right call.
Written in given, when, then format, these stay user-centric.
Example non-functional ACs
- Given I am a paramedic with 100,000 patient records in my area,
when I open the patient list on a fast connection,
then it is populated and interactive within 500ms. - Given I am signed in as one customer,
when I request another customer’s saved address by its identifier,
then the request is refused
and no address data is returned. - Given the postcode lookup service is unavailable,
when I add a delivery address,
then I can still enter it manually and complete my order. - Given I am using keyboard only,
when I move through the address form,
then every field, error, and button is reachable in a logical order.
Further examples covering load, injection, and failover are available in definition of done.
A non-functional AC is not an implementation preference. “Use Postgres rather than a document store” is a technical decision, possibly taken in service of a non-functional need, and it belongs in the implementation notes. The AC is the expectation the user or the business has; the database is one way of meeting it.
Who and when#
ACs are drafted in the Three Amigos conversation and strengthened by the team when the item is played back for estimation. They are not written alone by the Product Owner, Tech Lead, Delivery Lead or anyone else. Bringing diverse viewpoints to bear and deciding ACs through discussion is essential.
The test perspective is what stops the ACs being a restatement of the happy path. Product and development together will usually focus on what should happen, and it takes somebody with a critical mind who asks “how could this fail?” to uncover the edge cases.
ACs and slicing#
A long list of ACs is usually an indicator that the item should be split. Splitting by AC is often easy because the work of finding the seams is already done: each AC, or small group of ACs, is a candidate item in its own right. See feature slicing for how to judge whether the resulting pieces are genuine slices, and the questions to ask. Beyond five or six ACs, actively consider how the item could be split.
From ACs to tests#
Every AC should map to at least one test, at the cheapest level that can prove it. An AC about how a postcode is normalised is validated by a unit test. An AC about a saved address appearing at checkout crosses the stack and needs an end to end test. Working through the ACs and asking “what proves this, and at what level?” produces the high-level test approach almost as a by-product.
ACs are what a tester tests against, rather than an impression of whether the feature seems to work, and what a reviewer checks scope against: a pull request satisfying four of five ACs is not finished, and one satisfying seven has built something nobody asked for.
Key points#
- ACs are the shared, testable statement of what “working” means for one item, and the bridge between the user need and the tests.
- They complement the definition of done rather than duplicating it: one is specific to this item, the other applies to every item.
- Given, when, then is valuable because it forces a starting state and an observable outcome, both usually missing from prose ACs or brief bullet points.
- A good AC is observable, testable before the code exists, behavioural rather than describing implementation, about one thing, and written in the user’s language, including errors and edge cases.
- Non-functional expectations are user needs and belong on the story that introduces the behaviour, with expectations quantified.
- ACs are drafted with product, development, and test perspectives present, not written alone and circulated.
- A long list of ACs is a signal that the item should be split.
- Each AC should map to at least one test, at the cheapest level that can prove it.
Mistakes to avoid
- ACs that describe the implementation. Naming components, tables, or endpoints ties acceptance to a decision that may change while the behaviour does not.
- ACs only for the happy path. If every AC describes success, the test perspective was missing from the conversation.
- Untestable words. Fast, intuitive, robust, seamless, and user-friendly all feel like requirements and none can be tested. Replace each with an observable outcome and, where relevant, a number.
- Repeating the definition of done on every item. It lengthens the list and buries the real ACs.
- Adding ACs mid-implementation without a conversation. New information is welcome, silent scope growth is not. Raise it, and discuss whether the item is now too big.
- Treating designs as a substitute for ACs, or the reverse. The design shows what it looks like; the ACs say what it does.
- A separate NFR document. Expectations not attached to an item being built tend to be ignored.