Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

Executable specifications turn requirements into tests your build runs. Learn how they work, how they differ from test cases, and how to write and run them.

Bhavya Hada
Author

Abhishek Mishra
Reviewer
Published on: August 26, 2026
Three people read the same discount requirement: the product owner meant one thing, the developer built another, and the tester checked a third. Executable specifications end that split by writing each requirement as a test the build server runs on every commit.
Capgemini's World Quality Report 2025-26 ranks soft skills, both verbal and written, as the fifth most critical skill for quality engineers at 51%, which puts written clarity ahead of most tooling questions.
This guide covers what executable specifications are, how they differ from test cases and automated tests, how to write one in Gherkin, where they belong in the test pyramid, and how to run them in CI.
Overview
Executable specifications are requirements written so a machine can run them as tests. A product person reads the specification and confirms it is right; a test framework runs the same file and proves the system still matches it. The specification lives in version control beside the code, so it cannot silently go out of date.
Are executable specifications the same as test cases?
What tools support executable specifications?
Cucumber, SpecFlow, Behave, and Gauge bind plain-language files to step definitions in Java, .NET, Python, and JavaScript. Jest, RSpec, and pytest qualify when test names read as requirements. TestMu AI adds natural-language authoring through KaneAI and plain-English test files through Kane CLI.
Executable specifications are requirements written so a machine can run them as tests. The requirement text names the test, worked examples supply the data, and a passing run proves the system still matches it.
You will also see them called executable requirements, a name that dominates in regulated and embedded work where each scenario has to be traced to a numbered requirement. Whichever label a team uses, three properties have to hold at once, and dropping any one of them produces something else:
The same requirement looks very different in each form. Here is one discount rule written first as prose and then as a runnable specification:
| Aspect | Prose requirement | Executable specification |
|---|---|---|
| Wording | The system shall apply a percentage discount to eligible orders. | Given a cart of 40 dollars, When the code SAVE10 is applied, Then the total is 36 dollars. |
| Ambiguity | Eligible is undefined, and nobody knows whether the discount applies before or after shipping. | The numbers force the answer. Disagreement surfaces while writing the example, not in production. |
| Verification | Someone reads the document and forms an opinion. | The pipeline runs it and reports a result that nobody has to interpret. |
| Decay | Silent. The document stays confident while the code moves on. | Loud. A statement that stops being true fails the next run. |
Executable specifications in software development grew out of two named practices. Dan North's behavior driven development supplied the Given, When, Then grammar, and Gojko Adzic's specification by example supplied the discipline of deriving every scenario from a concrete, agreed example rather than an abstract rule. The term living documentation describes the by-product: a suite that documents current behaviour because it is executed rather than reviewed.
If your team still writes requirements as prose first, the practical starting point is a well-formed software requirement specification and a habit of turning each numbered criterion into one worked example.
Executable specifications work through four separated layers: the specification in business language, a domain language that names the actions, a driver that talks to the running system, and the system itself under test.
Dave Farley popularised this four-layer split in continuous delivery work, and it is the single design decision that determines whether a suite survives two years of UI churn. Each layer knows only about the layer directly below it.
| Layer | What lives here | What breaks it |
|---|---|---|
| 1. Specification | The scenario in business language. A .feature file, a table, or a plain-English test file. | A genuine change in the business rule. Nothing else should touch this file. |
| 2. Domain language | Reusable actions named after intent, such as applyDiscountCode or placeOrder. | A new business concept that has no name yet. |
| 3. Protocol driver | The only layer that knows about selectors, endpoints, and page structure. | A renamed button, a restructured DOM, a changed API route. Fix it once here. |
| 4. System under test | The deployed application, running in a production-like environment. | A real defect, which is the only failure you actually want. |
Teams that skip layers two and three write scenarios full of clicks and field names. When the login page is redesigned, every one of those scenarios fails at once and the specification has to be rewritten even though the business rule never changed. That is the failure mode behind most abandoned suites, and it is covered in more depth in these BDD pitfalls.
Acceptance criteria state the pass bar in prose, a test case lists steps for a person or script to follow, and an executable spec is the criterion itself written in a runnable form. The spec removes that hand-off.
These four artifacts get used interchangeably in most teams, which is why the same behaviour ends up documented in four places that disagree. They are distinguishable on four axes:
| Artifact | Written for | Machine-runnable | Fails when |
|---|---|---|---|
| Acceptance criterion | The team, during refinement. Defines done for one story. | No | Never. It is a statement, so it can be wrong indefinitely. |
| Test case | The tester who will execute it. Steps, data, expected result. | Only after someone automates it separately | A person runs it and records a result. |
| Automated test | The engineer maintaining the suite. Often asserts internals. | Yes | The assertion fails, whether or not a business rule changed. |
| Executable specification | The person who requested the behaviour, and the machine. | Yes | The stated behaviour stops being true. |
The practical consequence is that a specification suite collapses three of these into one artifact. Instead of writing a criterion, then a test case, then an automation script, the team writes the criterion once as a concrete example and binds it to code. Worked examples of that first conversion step are collected in these acceptance criteria examples.
No. Every executable specification is an automated test, but most automated tests are not specifications. A test earns the name only if the person who asked for the behaviour can read it and confirm that it is correct.
Apply three checks to any test in your suite. It qualifies as a specification when all three pass:
Most suites contain both kinds and should. A unit test asserting that a date parser rejects the 30th of February is valuable and will never be a specification, because no stakeholder asked for it in those words. The mistake is expecting a folder of assertion-level tests to serve as documentation, and then wondering why nobody outside engineering ever reads them.
Note: Writing the binding layer is where most teams stall, because it needs someone who can code. TestMu AI's KaneAI authors the whole flow from a plain-English prompt, a Jira ticket, or a PRD, then exports the result to Selenium, Playwright, Cypress, or Appium so the team keeps its own framework. Start free
Behavior driven development runs a conversation that produces concrete examples, and Gherkin writes them in the Given When Then pattern. A step definition file then binds each line to code that drives the application.
Gherkin is a small, deliberately limited grammar. The Gherkin reference defines the full keyword set, but four of them carry almost every scenario you will write:
A Scenario Outline is the highest-value construct in the language and the most commonly skipped. This one specification replaces four near-identical scenarios and makes the boundary at 100 dollars visible at a glance:
Feature: Checkout discounts
Scenario Outline: Free shipping applies above the threshold
Given a shopper has a cart worth <cart> dollars
When they proceed to checkout
Then the shipping charge is <shipping> dollars
Examples:
| cart | shipping |
| 99 | 5 |
| 100 | 0 |
| 101 | 0 |
| 0 | 0 |The last row is the one that earns the table. A cart worth nothing should probably not qualify for free shipping, and writing the example is what forces someone to decide. Teams new to the grammar usually get more value from reading real Gherkin test cases than from the keyword list, and the wider practice split is covered in TDD vs BDD.
Start from one acceptance criterion, write a concrete example with real values, phrase each step as an observable outcome rather than a click, bind the steps to a driver, and run it in the pipeline that gates merges.
The five steps below take a single requirement all the way to a green run. The example is deliberately small so the mechanics stay visible.
Here is the specification for a single-input form on the TestMu AI Selenium Playground. Note that no step mentions an element:
Feature: Simple form submission
Scenario: A single input field echoes the submitted message
Given the user is on the Simple Form Demo page
When the user submits the message "Executable specs are runnable requirements"
Then the page displays that exact messageThe step definitions carry every selector, and the cloud capabilities live beside them so the same specification can run locally or on a grid without a single edit to the feature file:
const { Given, When, Then } = require('@cucumber/cucumber');
const { chromium, expect } = require('@playwright/test');
const capabilities = {
browserName: 'Chrome',
browserVersion: 'latest',
'LT:Options': {
platform: 'Windows 11',
build: 'Executable Specifications Blog',
name: 'Scenario: A single input field echoes the submitted message',
user: process.env.LT_USERNAME,
accessKey: process.env.LT_ACCESS_KEY,
},
};
Given('the user is on the Simple Form Demo page', async function () {
this.browser = await chromium.connect(
'wss://cdp.lambdatest.com/playwright?capabilities=' +
encodeURIComponent(JSON.stringify(capabilities))
);
this.page = await this.browser.newPage();
await this.page.goto('https://www.testmuai.com/selenium-playground/simple-form-demo/');
});
When('the user submits the message {string}', async function (message) {
this.message = message;
await this.page.fill('#user-message', message);
await this.page.click('#showInput');
});
Then('the page displays that exact message', async function () {
await expect(this.page.locator('#message')).toHaveText(this.message);
await this.browser.close();
});Those three steps were executed against the Simple Form Demo page on the TestMu AI cloud grid on August 26, 2026. The run log below is the real output, and the screenshot is the page state at the moment the Then step asserted:
[Given] Simple Form Demo page loaded -> Selenium Grid Online | Run Selenium Test On Cloud
[When] message entered and submitted
[Then] displayed message = "Executable specs are runnable requirements"
RESULT: 1 scenario (1 passed), 3 steps (3 passed)
Notice what the feature file does not contain: no selector, no URL, no wait. Redesign that form and only the step definition changes. The same separation applies when the driver is Playwright rather than Selenium, which is walked through in this guide to Playwright with Cucumber.
They usually live at the acceptance layer, but the same spec can be driven at unit, integration, and acceptance level by swapping the protocol driver. Running it low gives speed, and running it high gives confidence.
This is the part almost every guide skips, and it follows directly from the four-layer split. Because layer three is the only layer that knows how to reach the system, one feature file can be pointed at three different entry points.
| Layer | Driver calls | Typical feedback | What it proves |
|---|---|---|---|
| Unit | Domain methods directly, with test doubles for anything external. | Seconds, on save | The business rule is implemented correctly in isolation. |
| Integration | The local HTTP or service boundary, with real containers for stores. | Minutes, on commit | The rule survives wiring, serialisation, and persistence. |
| Acceptance | A real browser or device against a deployed environment. | Tens of minutes, on merge | A user can actually complete the journey the rule describes. |
Reusing one specification across two layers costs a second driver and buys much earlier feedback on the same business rule. Reusing it across all three is rarely worth the maintenance, so most teams pick the unit layer for rule-heavy domains and the acceptance layer for journey-heavy products. Where those journeys cross acceptance testing boundaries, keep the specification identical and let only the driver change.
Run them as a required check on every pull request. Tag the fast specs to run on commit and the full suite on merge, publish the report as a build artifact, and fail the job on any undefined or pending step.
Executable specifications testing only pays for itself when a failing scenario can block a merge. A suite that runs nightly and gets ignored by 10am is documentation with a cron job attached. Four settings do most of the work:
name: executable-specs
on: [pull_request]
jobs:
specs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- name: Run the specification suite
env:
LT_USERNAME: ${{ secrets.LT_USERNAME }}
LT_ACCESS_KEY: ${{ secrets.LT_ACCESS_KEY }}
run: npx cucumber-js --strict --tags "@smoke" --parallel 4 --format html:reports/specs.html
- uses: actions/upload-artifact@v4
if: always()
with:
name: specification-report
path: reports/specs.htmlThe --strict flag is the one teams most often leave off, and it is the difference between a suite that reports coverage and a suite that has it. Scaling the same idea further is a matter of infrastructure rather than authoring, which is where a cloud grid replaces a queue of local runs.
Note: Acceptance-layer specifications are slow because they wait on browsers, not because they are badly written. TestMu AI runs them in parallel across 3,000+ browser and OS combinations and 10,000+ real devices, so the merge gate stays in minutes as the suite grows. Explore the test automation cloud
An AI coding agent reads and writes source code, so it cannot see whether the rendered page actually works. An executable spec gives the agent a machine-readable pass or fail that it can check its own output against.
The volume problem is now measurable. GitHub's Octoverse 2025 report counts 43.2 million pull requests merged each month, up 23% year over year, alongside nearly a billion commits in 2025. Review capacity did not grow 23%.
An agent's verification primitives are unit tests, type checkers, linters, and compilers, and every one of them operates on the same closed surface: text. None of them render the application, click a button, or confirm that a redirect lands on the right URL. That produces a specific failure class where the code is correct and the user-facing result is broken.
A specification written before the agent starts changes the loop in three ways:
Kane CLI is built around exactly this loop. It ingests a source of intent such as a PRD or a ticket, derives business use cases, scenarios, and acceptance criteria, and writes each one to a committable plain-English test.md file whose every step is wired to the criterion it proves. Running it drives a real Chrome browser and seals an evidence pack containing per-step screenshots, a HAR network log, and console output.
The coverage command is the part that matters for specifications. It reports which acceptance criteria were actually proved by the evidence rather than how many steps ran, and its strict flag demotes a green that was earned against a specification that has since changed. A number that is allowed to go down is one you can trust when it goes up. The Kane CLI getting started guide covers installation and the first run.
# derive use cases, scenarios and acceptance criteria from a requirement
kane-cli context ingest ./docs/checkout-prd.md
kane-cli design
# run the generated plain-English specification against a real browser
kane-cli testmd run ./tests/checkout_test.md
# report what the evidence actually proved, per acceptance criterion
kane-cli cover --strictThe broader shift toward agents owning parts of the quality loop is covered in this piece on agentic QA.
The measurable benefits are fewer requirement defects found late, a regression suite that costs nothing extra to build, and documentation that cannot go stale because a wrong sentence turns the build red.
Every benefit below has a mechanism and a metric attached, because a benefit you cannot measure is a preference. Baseline each one for a quarter before adopting the practice so the comparison means something:
| Benefit | Mechanism | Metric to track |
|---|---|---|
| Ambiguity found earlier | Concrete values force a decision during refinement instead of during development. | Defects tagged as requirement misunderstanding, per release. |
| Free regression suite | The artifact written to agree on behaviour is the same artifact that guards it later. | Scenarios added per sprint versus separately authored regression tests. |
| Documentation that stays true | Behavioural prose is executed, so an untrue statement fails rather than misleads. | Age of the newest behavioural doc that has never been verified. |
| Cheaper UI churn | Selector knowledge is confined to the driver layer, so one edit fixes a redesign. | Files touched per UI refactor, and hours spent repairing the suite. |
| Requirement-level coverage | Scenarios trace to criteria, so gaps are reported against rules rather than lines. | Percentage of acceptance criteria with at least one passing scenario. |
The last row is the one to lead with when asking for time to adopt this. Line coverage rises while risk stays flat, because executing a line is not the same as proving a requirement. Coverage measured per acceptance criterion is the only number that answers which rules are unverified, and it is the number a release conversation actually needs.
Skip them when no non-programmer will ever read the specification, when the behaviour is easier to state in code than in prose, or when nobody outside engineering will join the conversation that produces the examples.
The practice has a real cost, and every competing guide on this topic leaves it out. Four situations where the cost exceeds the return:
One further warning applies even to teams that should adopt the practice: step definition sprawl. Ten near-identical phrasings of the same action produce ten bindings that drift apart, and the suite becomes harder to change than the code it guards. Enforce a shared step vocabulary in review from the first scenario, and treat a new step phrasing as a design decision rather than a convenience. The formal variant of this discipline is covered under acceptance test driven development.
Key Takeaways
Pick the single acceptance criterion that caused the most rework in your last release and rewrite it as one scenario with real values in it. Bind it to a driver, add it to the pull request check, and see whether the team agrees on what the numbers should be. That one file will tell you more about your requirements process than a month of refinement meetings.
If the binding layer is the blocker, TestMu AI's KaneAI authors and maintains the executable half from natural language while the specification stays yours, and self-healing re-anchors steps when the interface changes instead of failing on a stale selector. The KaneAI documentation walks through authoring a first test from a requirement, and the wider practice of moving verification earlier is covered in shift left testing.
Author
Bhavya Hada is a Community Contributor at TestMu AI with over three years of experience in software testing and quality assurance. She has authored 20+ articles on software testing, test automation, QA, and other tech topics. She holds certifications in Automation Testing, KaneAI, Selenium, Appium, Playwright, and Cypress. At TestMu AI, Bhavya leads marketing initiatives around AI-driven test automation and develops technical content across blogs, social media, newsletters, and community forums. On LinkedIn, she is followed by 4,000+ QA engineers, testers, and tech professionals.
Reviewer
Abhishek Mishra is a Technical Product Manager at TestMu AI, where he owns Test Manager, the test management product. He has over 8 years of experience in product management and market analysis. His expertise spans across AI-native software testing, product strategy, and analytics. Previously, Abhishek served as the Product Lead at IndiaClan and co-founded Gartley618 Technologies, where he led innovative projects in quantitative trading and blockchain. He holds a B.Tech degree.
Did you find this page helpful?
More Related Blogs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance