TDD Guide

Red-Green-Refactor Cycle

// STEP 1 (RED): Write a failing test // test for a feature that doesn't exist yet test('FizzBuzz returns "Fizz" for multiples of 3', () => { expect(fizzBuzz(3)).toBe('Fizz'); // โŒ fizzBuzz is not defined expect(fizzBuzz(6)).toBe('Fizz'); expect(fizzBuzz(9)).toBe('Fizz'); }); // STEP 2 (GREEN): Write the minimum code to make it pass function fizzBuzz(n) { if (n % 3 === 0) return 'Fizz'; // โœ… only what's needed return String(n); } // STEP 3 (REFACTOR): Improve the code without breaking tests // Now add more tests, then more code: test('FizzBuzz returns "Buzz" for multiples of 5', () => { expect(fizzBuzz(5)).toBe('Buzz'); expect(fizzBuzz(10)).toBe('Buzz'); }); test('FizzBuzz returns "FizzBuzz" for multiples of 15', () => { expect(fizzBuzz(15)).toBe('FizzBuzz'); }); // Final implementation: function fizzBuzz(n) { if (n % 15 === 0) return 'FizzBuzz'; if (n % 3 === 0) return 'Fizz'; if (n % 5 === 0) return 'Buzz'; return String(n); }

TDD Approaches

ApproachDirectionStart WithGood For
Inside-Out (Detroit/Chicago)Units first, integrate laterDomain objects, pure logicWell-understood domain, algorithms
Outside-In (London/Mockist)Acceptance test first, mock collaboratorsHigh-level acceptance testAPI-driven design, unknown internals
BDD (Behavior-Driven)User scenarios firstGherkin feature filesCross-team communication, acceptance criteria

BDD with Gherkin

# Feature file (Gherkin syntax) Feature: User login As a registered user I want to log in to my account So that I can access my dashboard Scenario: Successful login Given I am on the login page When I enter email "user@example.com" and password "correct123" And I click the "Log In" button Then I should be redirected to the dashboard And I should see "Welcome back, User" Scenario: Failed login with wrong password Given I am on the login page When I enter email "user@example.com" and password "wrong" And I click the "Log In" button Then I should see "Invalid email or password" And I should remain on the login page # Step definition (JavaScript โ€” Cucumber.js) Given('I am on the login page', async () => { await page.goto('/login'); }); When('I enter email {string} and password {string}', async (email, password) => { await page.fill('#email', email); await page.fill('#password', password); });