TDD / BDD
TDD / BDD
Test-Driven Development & Behavior-Driven Development
1. Overview of TDD/BDD, Development Methodologies That Drive Design by Writing Tests First and Build In Quality
flowchart LR
A["Tests added after code<br/>is written<br/>(quality trails, fragile to regression)"] --"Test-first<br/>design-driven approach"--> B["Red-Green-Refactor<br/>repeated in short cycles"] --"Behavior specification<br/>(Given-When-Then)"--> C["Early defect detection,<br/>improved design quality"]
style A fill:#FFEBEE,stroke:#D32F2F,color:#000
style B fill:#E3F2FD,stroke:#1976D2,color:#000
style C fill:#E8F5E9,stroke:#388E3C,color:#000
Definition:
- TDD (Test-Driven Development): A development methodology in which a failing unit test is written first, before the implementation code, followed by writing the minimal code to pass the test, and then refactoring — repeating this Red-Green-Refactor cycle.
- BDD (Behavior-Driven Development): An extension of TDD that specifies a system’s behavior from a business perspective, using the Given-When-Then scenario language to build shared understanding among developers, QA, and the business.
Characteristics: (Design specification role) Tests double as design specifications, ensuring alignment between requirements and implementation. (Early defect detection) A short feedback loop (within minutes) enables early detection and correction of defects, curbing technical debt. (Refactoring safety net) Test code acts as a safety net for refactoring — guaranteeing existing behavior when improving structure.
2. Core Structure of TDD/BDD
A. The Red-Green-Refactor Cycle
flowchart TD
RED["RED<br/>Write a failing test<br/>no implementation yet<br/>confirm the test fails"]
GREEN["GREEN<br/>Write the minimal code<br/>needed to pass the test<br/>pass quickly"]
REF["REFACTOR<br/>Improve code quality<br/>remove duplication, clean up structure<br/>tests still pass"]
RED -->|"Write implementation code"| GREEN
GREEN -->|"Improve code"| REF
REF -->|"Write the next test"| RED
style RED fill:#dc3545,stroke:#c82333,color:#fff
style GREEN fill:#28a745,stroke:#218838,color:#fff
style REF fill:#E3F2FD,stroke:#1976D2,color:#000
| Phase | Purpose | Core Principle |
|---|---|---|
| RED (Fail) | Specify requirements as a test before implementation | New feature work must start with a failing test |
| GREEN (Pass) | Implement the minimum needed to pass the test | The goal is simply to pass, even if not perfect |
| REFACTOR (Improve) | Remove duplication, improve naming, clean up structure | Improve code quality while keeping tests passing |
The Three Rules of TDD (Uncle Bob)
| Rule | Content |
|---|---|
| Rule 1 | You are not allowed to write production code until you have written a failing unit test |
| Rule 2 | You are not allowed to write more of a unit test than is sufficient to fail — and not compiling counts as failing |
| Rule 3 | You are not allowed to write more production code than is sufficient to pass the currently failing test |
B. Given-When-Then Scenarios (Linked to BDD)
flowchart LR
subgraph GWT["Given-When-Then Structure"]
direction TB
GIV["Given (Precondition)<br/>defines the system's initial state<br/>sets up the environment before the test runs"]
WEN["When (Action)<br/>a specific action by the user or system<br/>executes the behavior under test"]
THN["Then (Outcome)<br/>verifies the expected result/state<br/>confirms the system's response"]
GIV --> WEN --> THN
end
subgraph TOOLS["BDD Tools"]
direction TB
T1["Cucumber<br/>(Gherkin language)"]
T2["JBehave<br/>(Java BDD)"]
T3["Behave<br/>(Python BDD)"]
T4["Jest + Describe<br/>(JS/TS BDD)"]
end
GWT --> TOOLS
style GIV fill:#E3F2FD,stroke:#1976D2,color:#000
style WEN fill:#FFF3E0,stroke:#F57C00,color:#000
style THN fill:#E8F5E9,stroke:#388E3C,color:#000
style TOOLS fill:#F3E5F5,stroke:#7B1FA2,color:#4A148C
Given-When-Then Scenario Example
Feature: Online shopping cart
Scenario: Add a product to the cart
Given the customer is logged in
And the product "Laptop" has 5 units in stock
When the customer adds 1 unit of "Laptop" to the cart
Then the cart should contain 1 unit of "Laptop"
And the stock should be 4 units| Component | Role | Corresponding TDD Element |
|---|---|---|
| Given | Sets up test preconditions and initial state | @Before / setUp() |
| When | Executes the action under test | Invoking the method under test |
| Then | Verifies the expected outcome (assert) | assertEquals() / assertThat() |
| And / But | Adds additional conditions or outcomes | Chaining multiple Given/When/Then steps |
TDD vs. BDD Comparison
| Comparison Item | TDD | BDD |
|---|---|---|
| Perspective | Developer-centric (unit-level functionality) | Business-behavior-centric (scenarios) |
| Writing language | Programming language (Java, Python) | Near-natural-language Gherkin |
| Collaboration audience | Among developers | Developers, QA, and the business together |
| Test unit | Method/class level | User scenario (Feature) level |
| Representative tools | JUnit, pytest, Jest | Cucumber, JBehave, Behave |
3. Expected Benefits and Application of TDD/BDD
| Category | Key Expected Benefits | Application and Practical Approach |
|---|---|---|
| Built-in quality | Early defect detection minimizes correction cost (the 1:10:100 rule) | Set up a CI pipeline gate that automatically runs TDD tests |
| Improved design | Testable code naturally leads to single responsibility and low coupling | Build a TDD-based safety net before restructuring legacy code |
| Stronger collaboration | BDD scenarios build shared understanding across business, development, and QA | Define acceptance criteria with Given-When-Then during sprint planning |
| Regression prevention | Automated test code continuously guards against regression | Automatically run the full test suite in the CD pipeline |