Introduction

Kent Beck's "Test-Driven Development: By Example" is a seminal work that introduced many developers to TDD. This article explores key concepts and practical examples from the book.

Money Example: A Classic TDD Case Study

One of the most famous examples from the book is the Money class implementation. Let's see how it demonstrates TDD principles:


// First Test: Equality
test('should consider same amount as equal', () => {
    const five = new Dollar(5);
    expect(five.equals(new Dollar(5))).toBe(true);
    expect(five.equals(new Dollar(6))).toBe(false);
});

// First Implementation
class Dollar {
    constructor(amount) {
        this.amount = amount;
    }

    equals(dollar) {
        return this.amount === dollar.amount;
    }
}

// Second Test: Multiplication
test('should multiply amount correctly', () => {
    const five = new Dollar(5);
    let product = five.times(2);
    expect(product.amount).toBe(10);
    product = five.times(3);
    expect(product.amount).toBe(15);
});

// Updated Implementation
class Dollar {
    constructor(amount) {
        this.amount = amount;
    }

    equals(dollar) {
        return this.amount === dollar.amount;
    }

    times(multiplier) {
        return new Dollar(this.amount * multiplier);
    }
}
            

Key Lessons from the Book

  • Start with the simplest test that could possibly work
  • Make the test pass with the simplest implementation
  • Refactor to remove duplication
  • Repeat the cycle

Test Naming Best Practices

Following Clean Code principles, test names should be:

  • Descriptive and self-documenting
  • Follow a consistent pattern
  • Include the scenario being tested
  • Indicate the expected outcome

Example: Improved Test Names


describe('Dollar', () => {
    test('should return true when comparing equal amounts', () => {
        const five = new Dollar(5);
        expect(five.equals(new Dollar(5))).toBe(true);
    });

    test('should return false when comparing different amounts', () => {
        const five = new Dollar(5);
        expect(five.equals(new Dollar(6))).toBe(false);
    });

    test('should create new Dollar instance when multiplying', () => {
        const five = new Dollar(5);
        const product = five.times(2);
        expect(product).toBeInstanceOf(Dollar);
        expect(product.amount).toBe(10);
    });
});
            

Conclusion

Kent Beck's approach to TDD emphasizes simplicity, clarity, and incremental development. By following these principles, we can create more maintainable and reliable code.

"The act of writing a unit test is more an act of design than of verification. It is also more an act of documentation than of verification." - Kent Beck