Skip to content

TDD Double Loop

The TDD Double Loop is a powerful development methodology that combines Behavior-Driven Development (BDD) with traditional Test-Driven Development (TDD). It creates two nested feedback loops that guide you from user requirements to working code.

What is the Double Loop?

The Double Loop consists of two feedback cycles operating at different timescales:

LoopTimescaleFocusTools
Outer Loop (BDD)Hours to DaysUser behavior, business requirementsPest BDD, Cucumber, Behat
Inner Loop (TDD)MinutesImplementation details, code designPest, PHPUnit
Double Loop TDD & BDD Workflow Diagram

The Core Idea

Start from the outside, work inward.

  1. Write a failing behavior test (BDD) that describes what the user wants
  2. Write failing unit tests (TDD) to build the components needed
  3. Make unit tests pass with minimal code
  4. Watch the behavior test pass
  5. Refactor with confidence
┌─────────────────────────────────────────────────────────────┐
│                      OUTER LOOP (BDD)                       │
│                                                             │
│   Feature: User Registration                                │
│     Scenario: User registers successfully                   │
│       Given I am on registration page                       │
│       When I submit valid credentials         ◄── FAILING   │
│       Then I should have an account                         │
│                                                             │
│   ┌─────────────────────────────────────────────────────┐   │
│   │                  INNER LOOP (TDD)                   │   │
│   │                                                     │   │
│   │   test('creates user with hashed password')         │   │
│   │   test('sends welcome email')                       │   │
│   │   test('logs user in')                              │   │
│   │                                                     │   │
│   │   RED → GREEN → REFACTOR → RED → GREEN → ...        │   │
│   │                                                     │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│   ✓ Scenario: User registers successfully     ◄── PASSING   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Why Use the Double Loop?

1. Outside-In Development

You start with what users need and work inward to implementation:

User Need → Feature → Steps → Service → Model → Database

This ensures you never build features nobody asked for.

2. Two Levels of Confidence

LevelWhat It TestsWhat It Catches
Behavior TestsBusiness requirementsMissing features, wrong behavior
Unit TestsImplementation detailsBugs, edge cases, regressions

3. Living Documentation

Feature files serve as always-accurate, executable documentation:

gherkin
# This IS the specification - and it runs!
Feature: Shopping Cart
  Scenario: Add item to cart
    Given I have an empty cart
    When I add "iPhone 15" to the cart
    Then my cart should contain 1 item

4. Refactoring Safety

Change implementation freely - if behavior tests pass, user experience is preserved:

bash
# Refactor internals completely
# As long as this passes, users are happy:
pest --bdd
# ✓ User can register
# ✓ User can add items to cart
# ✓ User can checkout

The Critical Rule

Test Must Fail First

A test that passes the first time (before code is written) means one of:

  • The test is inaccurate or poorly written
  • The test is not added to the test suite
  • The code/feature already exists

If a new test passes immediately, investigate why!

When to Use Each Loop

Use the Outer Loop (BDD) for:

  • New features
  • User-facing behavior
  • Business requirements
  • Integration scenarios
  • Acceptance criteria

Use the Inner Loop (TDD) for:

  • Implementation details
  • Edge cases
  • Error handling
  • Performance optimization
  • Internal APIs

Double Loop vs Classic TDD vs Traditional Testing

AspectTraditionalClassic TDDDouble Loop
Test writingAfter codeBefore codeBefore code
Starting pointImplementationUnit/ClassUser requirement
DirectionInside-outInside-outOutside-in
Test scopeOften mixedUnit focusedClearly separated (BDD + TDD)
Business visibilityLowLowHigh (Gherkin readable)
DocumentationSeparate from testsTests as docs (technical)Tests ARE documentation (business)
RefactoringRiskySafe (unit level)Safe (behavior + unit level)
Feedback loopNoneSingle (RED-GREEN-REFACTOR)Double (BDD → TDD → BDD)
Stakeholder involvementAfter developmentRarelyFrom the start

Section Contents

This section covers:

  1. The Workflow - Step-by-step guide to the Double Loop process
  2. TDD Schools - London vs Chicago approaches
  3. Tutorial - Complete hands-on example

Further Reading

Released under the MIT License.