BDD: Make the Business Write Your Tests
What if the business wrote the tests, and developers just made them pass?
That's the promise of behavior-driven development (BDD). Instead of developers guessing at requirements, chasing Slack threads, and interpreting vague Jira tickets, we let the people who know the why express it in a form that's precise enough to execute.
Throughout my career, I've worked with teams of all shapes and sizes, and one pattern is universal:
nobody loves writing tests. Most developers grudgingly agree they're important, but tests are often seen
as a tax—time spent writing code that doesn't "ship features."
The result is predictable: coverage gaps, brittle suites, and requirements that live in Confluence but never make it into code. Testing becomes a burden instead of a superpower.
BDD flips that dynamic. Instead of treating tests as a chore, it turns them into a shared language between developers, QA, and the business. Suddenly, everyone is speaking the same language about features and scenarios, and tests become the living documentation of what the system is supposed to do.
Before we dive into how this works, let's establish a few "Laws of Testing." These aren't divine truths, but they're a solid starting point—guidelines that help ensure tests actually drive design instead of just describing what already exists.
The Laws of Testing
- No application code will be written until tests are defined.
- Systems should be tested as they are meant to be used.
- Automate tests to the maximum extent technically and financially feasible.
- Every business requirement must have a corresponding test. If the requirement changes, the test must change.
- Any code not covered by realistic, automated tests should be treated as magic—and magic should not be trusted.
Notice that I'm not prescribing a specific tool, framework, or level of granularity. These laws simply give you a pragmatic foundation to make testing a first-class part of building software, not an afterthought.
Behavior-Driven Development
Now for the fun part: putting this into practice.
Behavior-Driven Development (BDD) is designed to bridge the gap between business stakeholders, users, developers, QA, and everyone else involved in a project. There are many flavors of BDD, but at their core, they all focus on telling cohesive, testable stories using a shared Domain-Specific Language (DSL).
There's a long-standing joke in IT—still true even in the post-ChatGPT era—that it's easier to teach a subject-matter expert to code than it is to get them to clearly articulate what they actually want built.
Over the years, countless tools have promised to help non-technical folks bring their ideas to life, but theory and practice rarely align. Everything works in theory. We can keep building better tools to bridge the gap between decision-makers and developers, but no tool can prevent the inevitable: requirements change.
Business needs evolve constantly. Even in a perfectly stable market, a company's technology stack would still have to adapt—whether to security updates, API deprecations, or new compliance requirements. That's why business and technology teams need a living contract: a shared, human-readable specification of what's supposed to exist, expressed in language that everyone can understand.
BDD provides exactly that. It takes the "what" from the business and turns it into executable specifications for developers, ensuring the system stays aligned with today's needs—not just the assumptions written down last quarter.
What BDD Actually Is
Behavior-Driven Development (BDD) is essentially turning your acceptance criteria into executable code.
If your company already writes:
- Acceptance Criteria in Jira or Azure DevOps
- Business Requirement Documents (BRDs) in Word or Confluence
- Test Scripts for QA teams to follow manually
…you're already halfway there. BDD simply takes those artifacts, expresses them in a precise, human-readable format, and wires them into your test suite so they can be run automatically.
Instead of existing only as text that humans must interpret, your requirements become living specifications that are always in sync with what the system actually does. If the system drifts, the tests fail — letting you catch gaps before production users do.
Key ideas:
- Ubiquitous language: agree on domain terms and reuse them in requirements, tests, and code.
- Outside-in: start from observable outcomes (what users and the business care about) and let those drive your implementation.
- Executable documentation: your feature files become a source of truth that stays up to date because failing tests force the team to update them when the business changes its mind.
Why It Clicks with the Business
BDD speaks the same language the business already uses.
Instead of:
"Verify that gold members receive free shipping on orders over $10."
Buried in a PDF or Confluence page, we can write:
Scenario: Gold member gets free shipping
Given the customer is a "gold" member
And they have a cart totaling $12.00
When they checkout with standard shipping
Then the shipping cost is $0.00
And the order total is $12.00
Stakeholders can read and confirm this just like they'd review an acceptance test — but now this doubles as a machine-executable test that can be run in CI.
How to Start Without Overhauling Everything
You don't need to replace all your documentation overnight. Try this:
- Take an existing acceptance criterion for a small feature.
- Rewrite it as a Gherkin scenario.
- Wire up just enough step definitions to make it run.
- Let it fail (red).
- Write or adjust code until it passes (green).
- Refactor code and scenario until both are clear and maintainable.
That's it — you've just done outside-in development. Over time, you can replace more of your static BRDs and test scripts with living specs that run automatically and stay current.
By framing BDD as an evolution of what teams already do, it becomes less intimidating: you're not adding "one more thing," you're making what you already write executable, consistent, and always up to date.
Starting from Existing Code (The Developer + QA Perspective)
Of course, not every team has pristine requirements or well-maintained acceptance criteria.
Sometimes the only source of truth is the code itself, or a set of outdated manual test scripts in a shared folder.
That's okay — you can still apply BDD principles to what you already have.
Step 1: Surface What the Code Already Does
Start by exploring the system from the outside in, and not by reading the code first.
- Walk through the application like a user would: click buttons, submit forms, run API calls.
- Write down what you observe in plain language, almost as if you were writing a support guide.
- Identify key flows: logins, purchases, data exports, admin tasks, error handling.
You're essentially reverse-engineering the behavior that already exists. The goal isn't to perfectly model the internals, but to describe what happens when X occurs.
Step 2: Capture Behavior as Scenarios
Turn those observations into scenarios, even if they're manual at first.
Scenario: User can reset password
Given I am on the login page
When I click "Forgot password"
And I submit my email address
Then I receive a password reset link by email
And I can set a new password
This becomes your backfill documentation and a checklist you can use to validate future changes.
Step 3: Choose a Testing Library
Once you have a handful of scenarios, pick a suitable tool that matches your tech stack. It doesn't have to be fancy — choose something that can:
- Parse Gherkin or similar DSL (Cucumber, SpecFlow/Reqnroll, Behave, TinyBDD 😉, etc.)
- Run in your CI/CD pipeline
- Integrate with the type of app you have (UI automation, API tests, service-level tests)
Don't over-engineer at this stage. The goal is simply to make a scenario run end-to-end.
Step 4: Build Thin Step Definitions
When you wire up steps to code, keep the step definitions thin and reusable:
- Treat them like glue code — they orchestrate, not implement.
- Push logic into abstractions (page objects, API clients, domain helpers).
- Keep language aligned with the business terms you captured earlier.
This separation makes your steps easy to read and your automation maintainable even as your app changes.
Step 5: Automate the Most Valuable Flows First
Don't try to automate everything on day one. Pick a few high-value, low-volatility flows:
- Happy-path checkouts
- Core login and authentication
- Critical reporting or data pipelines
Start small, get them running reliably in CI, and expand gradually. The point is not to hit 100% coverage overnight, but to start to gain comfort and momentum in writing BDD tests end-to-end.
By working backward from the app's behavior, you create a bridge between what the code does and what the business expects even when no documentation exists. Over time, your automated scenarios become the new source of truth, letting developers and QA refactor or ship new features with confidence.
Bringing It All Together
Whether you're starting from crisp acceptance criteria or working backwards from a codebase that only lives in developers' heads, the goal of BDD is the same: close the gap between what the business needs and what the code does.
You don't have to overhaul your entire testing strategy in a single sprint. You just have to start:
- Write one scenario.
- Get it running end-to-end.
- Share it with your team.
- Keep going.
Over time, you'll build up a living specification that grows with the system, catching regressions early and making onboarding new developers dramatically easier.
What a Mature BDD Practice Looks Like
A well-adopted BDD process creates a feedback loop that keeps everyone aligned:
- Business & product teams write or review scenarios as part of refinement.
- Developers implement features by making those scenarios pass.
- QA contributes new scenarios for edge cases and validates existing ones stay green.
- CI/CD pipelines run the whole suite automatically, so everyone knows the current state of the system at a glance.
When this loop is healthy, you get a shared understanding of what "done" really means, and confidence that your software still works tomorrow, next quarter, and next year.
Final Thoughts
BDD isn't a silver bullet, but it is a forcing function for clearer requirements, more reliable software, and tighter collaboration across teams.
If you've ever wished the business could "just write the tests," BDD is the closest thing we have to that dream. Start small, stay consistent, and watch as those scenarios turn into a living, breathing specification that guides your development for years to come.