Deft
Ask AI

Search

Search skills, authors and topics

mattpocock / skills

tdd

Red-green-refactor workflow for building features and fixes one slice at a time.

Install

npx skills add https://github.com/mattpocock/skills --skill tdd

Good and Bad Tests

Good Tests

Integration-style: Test through real interfaces, not mocks of internal parts.

typescript
// GOOD: Tests observable behaviortest("user can checkout with valid cart", async () => {  const cart = createCart();  cart.add(product);  const result = await checkout(cart, paymentMethod);  expect(result.status).toBe("confirmed");});

Characteristics:

  • Tests behavior users/callers care about
  • Uses public API only
  • Survives internal refactors
  • Describes WHAT, not HOW
  • One logical assertion per test

Bad Tests

Implementation-detail tests: Coupled to internal structure.

typescript
// BAD: Tests implementation detailstest("checkout calls paymentService.process", async () => {  const mockPayment = jest.mock(paymentService);  await checkout(cart, payment);  expect(mockPayment.process).toHaveBeenCalledWith(cart.total);});

Red flags:

  • Mocking internal collaborators
  • Testing private methods
  • Asserting on call counts/order
  • Test breaks when refactoring without behavior change
  • Test name describes HOW not WHAT
  • Verifying through external means instead of interface
typescript
// BAD: Bypasses interface to verifytest("createUser saves to database", async () => {  await createUser({ name: "Alice" });  const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);  expect(row).toBeDefined();});
// GOOD: Verifies through interfacetest("createUser makes user retrievable", async () => {  const user = await createUser({ name: "Alice" });  const retrieved = await getUser(user.id);  expect(retrieved.name).toBe("Alice");});

Tautological tests: Expected value restates the implementation, so the test passes by construction.

typescript
// BAD: Expected value is recomputed the way the code computes ittest("calculateTotal sums line items", () => {  const items = [{ price: 10 }, { price: 5 }];  const expected = items.reduce((sum, i) => sum + i.price, 0);  expect(calculateTotal(items)).toBe(expected);});
// GOOD: Expected value is an independent, known literaltest("calculateTotal sums line items", () => {  expect(calculateTotal([{ price: 10 }, { price: 5 }])).toBe(15);});