Day 5 of 5

TDD and Coverage

Test-Driven Development writes tests before code. Red-Green-Refactor is the cycle: write a failing test, make it pass with the simplest code, then refactor. Today you will TDD a feature from scratch and read coverage reports.

javascript
// TDD: Write the test FIRST — it will fail (Red)
// src/cart.test.js
import { Cart } from './cart';

describe('Cart', () => {
  let cart;
  beforeEach(() => { cart = new Cart(); });

  test('starts empty', () => {
    expect(cart.items).toHaveLength(0);
    expect(cart.total).toBe(0);
  });

  test('adds items', () => {
    cart.add({ id: 1, name: 'Widget', price: 9.99 });
    expect(cart.items).toHaveLength(1);
    expect(cart.total).toBeCloseTo(9.99);
  });

  test('removes items', () => {
    cart.add({ id: 1, name: 'Widget', price: 9.99 });
    cart.remove(1);
    expect(cart.items).toHaveLength(0);
  });

  test('applies discount', () => {
    cart.add({ id: 1, name: 'Widget', price: 100 });
    cart.applyDiscount(10); // 10%
    expect(cart.total).toBeCloseTo(90);
  });
});
javascript
// Now write the minimum code to make tests pass (Green)
// src/cart.js
export class Cart {
  constructor() { this._items = []; this._discount = 0; }

  get items() { return [...this._items]; }

  get total() {
    const subtotal = this._items.reduce((s, i) => s + i.price, 0);
    return subtotal * (1 - this._discount / 100);
  }

  add(item) { this._items.push(item); }

  remove(id) { this._items = this._items.filter(i => i.id !== id); }

  applyDiscount(pct) { this._discount = pct; }
}
Tip: Coverage shows which lines ran, not whether behaviour is correct. Aim for high coverage on business logic; don't obsess over 100%.

Exercise: TDD a Feature

  1. Write failing tests for a Checkout class (subtotal/tax/total)
  2. Run tests and confirm they are red
  3. Write the minimum code to turn them green
  4. Refactor without breaking tests
  5. Generate a coverage report and identify uncovered branches

Day 5 Summary

Finished this lesson?