Testing in the Design Phase: How TDD Starts Before You Write Code

Testing in the Design Phase: How TDD Starts Before You Write Code

Test-driven development has a reputation as a coding technique. Write a failing test. Write the code to make it pass. Refactor. Repeat. That loop is real and valuable, but it starts too late.

By the time a developer opens their editor, the most expensive design decisions have already been made. The data model is sketched out. The API contract is assumed. The acceptance criteria are written in prose that means different things to different people. TDD at the code level is excellent. TDD at the planning level is where the real leverage lives.

The Design Phase Is Where Ambiguity Hides

Every software project accumulates assumptions. Assumptions about what "success" means for a given feature. Assumptions about edge cases. Assumptions about what happens when things go wrong.

In the design phase, those assumptions live in people's heads and in loosely written requirements. A ticket might say "users can reset their password." That sounds clear. But it conceals dozens of open questions:

  • What happens if the reset link has expired?
  • Can a user request multiple reset links in quick succession?
  • Does resetting a password invalidate existing sessions?
  • What happens if the email address is not in the system?
  • Is there a rate limit on reset attempts?

None of these questions are answered by the original requirement. They will all be answered at some point — either deliberately during design, or accidentally during implementation when someone makes an assumption that may be wrong.

TDD at the planning level means answering these questions before implementation begins, in a format that can be verified automatically.

Acceptance Criteria as Executable Tests

The shift is conceptually simple: write acceptance criteria as scenarios, not prose.

Prose acceptance criteria look like this:

The user should be able to reset their password by entering their email address. They should receive an email with a reset link. The link should expire after 24 hours.

Scenario-based acceptance criteria look like this:

Scenario: Successful password reset
  Given a registered user with email "user@example.com"
  When they submit a password reset request with that email
  Then they receive a password reset email within 2 minutes
  And the reset link in the email is valid for 24 hours

Scenario: Expired reset link
  Given a user has a password reset link that was issued 25 hours ago
  When they click the reset link
  Then they see an error message indicating the link has expired
  And they are prompted to request a new reset link

Scenario: Unknown email address
  Given an email address that does not exist in the system
  When a password reset is requested for that email
  Then the response is identical to the success case
  And no email is sent
  (Note: same response prevents user enumeration attacks)

These scenarios answer the open questions. They are also executable: tools like Cucumber, Behave, and Robot Framework can run Gherkin scenarios directly against a web application.

The acceptance criteria become the test suite. The definition of done is passing all scenarios. There is no ambiguity about what "working" means.

Example Mapping: The Technique Behind This

Example Mapping is a structured workshop technique developed by Matt Wynne for collaborative requirements discovery. It takes 25-30 minutes per user story and produces:

  • Rules: Business rules that govern the story
  • Examples: Concrete examples (scenarios) that illustrate each rule
  • Questions: Open questions that need answers before development starts

The format uses index cards or a digital equivalent. One colour for the story, one for rules, one for examples, one for questions.

Running example mapping before a sprint forces the team to confront their assumptions. Questions that surface during mapping ("what if the user is locked out?") are far cheaper to answer before implementation than after.

A story should not move to development until all question cards are resolved. This is a forcing function. It moves the cost of requirements clarity to where it belongs: before code is written.

BDD: The Connection Between Planning and Testing

Behaviour-Driven Development (BDD) is the bridge that connects planning-level TDD to implementation.

BDD scenarios written during planning become automated acceptance tests. Product managers, QA engineers, and developers collaborate on the scenarios. The Gherkin format is readable by non-technical stakeholders, so the scenarios can be reviewed and approved before development starts.

When implementation is complete, running the BDD scenarios either confirms that the feature works or identifies gaps. There is no interpretation involved — the scenarios were agreed during design, and either they pass or they do not.

*** Settings ***
Library    Browser

*** Test Cases ***
Password Reset Link Expires After 24 Hours
    Given a user requests a password reset
    When they attempt to use the link 25 hours later
    Then they should see the expired link error message
    And the "Request New Link" button should be visible

With HelpMeTest, you can take these acceptance scenarios and generate full Playwright tests from plain English descriptions. The test cases written during design become the automated regression suite that runs on every deployment.

What Good Design-Phase Testing Looks Like

A well-tested design phase produces:

Unambiguous acceptance criteria. Every behaviour is expressed as a concrete example with a given state, an action, and an expected outcome.

A list of resolved edge cases. The common paths are obvious. The edge cases — expiry, rate limiting, error states, concurrent requests — have explicit expected behaviours.

A shared vocabulary. BDD scenarios create a shared language between product, engineering, and QA. "The user sees the expired link error" means the same thing to everyone because it was written collaboratively.

An executable specification. The scenarios written during design can be run as tests during development and as regression tests after deployment.

The Developer Experience of Planning-Level TDD

When a developer picks up a ticket with well-formed acceptance scenarios, the experience is fundamentally different.

They know what to build. They know which edge cases are in scope. They know exactly what "done" means. They can run the acceptance tests as they work and see progress in concrete terms.

Compare that to picking up a ticket with prose requirements and a Figma mockup. The developer has to infer the rules, make assumptions about edge cases, and rely on a QA engineer to catch the assumptions that turn out to be wrong — often weeks later.

The information is not different. The format is. Scenarios are a forcing function for clarity. Prose allows ambiguity to hide.

Starting Small

You do not need to transform your entire planning process overnight. Start with one practice from this list:

For the next three tickets: Before writing code, list every edge case you can think of and write an expected outcome for each one.

For the next sprint planning: Pick one story and run a 20-minute example mapping session with the developer, product manager, and a QA engineer. Count the questions that surface.

For the next feature: Write the acceptance criteria in Gherkin format before development starts. At the end of implementation, verify that every scenario passes.

Each of these is a small experiment. Run it. Measure whether more edge cases are caught during design than during QA. That data will tell you whether to go further.

Testing in the design phase is TDD at its most leveraged. The earlier you define what "working" means, the earlier you catch the gap between that definition and reality.

Read more