Test Driven Development

So, what is TDD?

Test-Driven Development (TDD) is a technique for building software that guides software development by writing tests

- Martin Fowler

https://martinfowler.com/bliki/TestDrivenDevelopment.html
  1. Write a failing test
  2. Write code to make it pass
  3. Refactor to ensure clean code

🔴💚🔁

Refactor both your code and tests

Rules, you say?

The Three Laws of TDD

- Robert Martin

http://www.butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  1. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  1. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

Generalisation

Avoid writing code for the "general" case when you don't have to

describe('isPrime', () => {
  it('should be prime', () => {
    expect(isPrime(3)).toBe(true);
  });
});
const isPrime = (n) => {
  return n == 3;
};

Triangulation

Use a second assertion to drive a safer creation of the generic version

https://dmitripavlutin.com/triangulation-test-driven-development/

Image: CC-BY (Brenton Cleeland)
describe('isPrime', () => {
  it('should return true when prime', () => {
    expect(isPrime(3)).toBe(true);
    expect(isPrime(7)).toBe(true);
  });
});
const isPrime = (n) => {
  for (let i = 2; i <= n/2; i++) {
    if (n % i === 0) {
      return;
    }
  }
  return true;
};

Refactor

const isPrime = (n) => {
  let max = Math.sqrt(n);
  for (let i = 2; i <= max; i++) {
    if (n % i === 0) {
      return;
    }
  }
  return true;
};

Once you're happy with the code, think about and test negative cases

describe('isPrime', () => {
  it('should return false when not prime', () => {
    expect(isPrime(22)).toBe(false);
  });
});
const isPrime = (n) => {
  let max = Math.sqrt(n);
  for (let i = 2; i <= max; i++) {
    if (n % i === 0) {
      return false;
    }
  }
  return true;
};

Think about the edge cases

describe('isPrime', () => {
  it('should return false when passed one', () => {
    expect(isPrime(1)).toBe(false);
  });
});
const isPrime = (n) => {
  let max = Math.sqrt(n);
  for (let i = 2; i <= max; i++) {
    if (n % i === 0) {
      return false;
    }
  }
  return n > 1;
};
https://stackoverflow.com/a/40200710

Awesome-sauce 🍅

Let's recap

Only write the code required to make your test pass

Think about edge cases

TDD is a discipline and takes practice

Try using TDD on your next side project

Thank you 🙏🏻