Stop 12 · TestingTopics · 8/9

TDD Basics

Part of the Backend Developer Roadmap

In short

Most people write code, then tests if there's time left. TDD flips it: write a failing test first, then just enough code to pass. It feels slow for a day and pays off for months.

Test-Driven Development — writing a failing test before writing the implementation, then writing just enough code to make it pass, then refactoring.

The blob character measures a dress form with a tape before cutting the cloth.

Think of it like this

The tailor measures first

A good tailor doesn't cut cloth and then hope it fits. He takes measurements, notes them down, and only then cuts and stitches until it matches. In TDD, the test is your measurement. You write down what 'fits' first, then make the code match it.

Watch it happen

Red, green, refactor

Red
Green
Refactor

1/6Red: write a test for isValidPhone("9876543210") expecting true. It fails, since the function doesn't exist.

The big ideas

What you need to know

Watch it fail first

A test you've never seen fail might not test anything. Red proves it can catch a missing feature.

Tiny steps

One small behaviour per cycle. Short cycles keep you moving and out of long debugging sessions.

Refactor with a safety net

Because tests cover each behaviour, you can clean up code without fear of breaking it.

Tests become the spec

The test names tell anyone what the function must do, often better than comments.

See it in code

Walk through the code

ts
1// 1. RED: written first, fails because isValidPhone doesn't exist yet2test("accepts a 10-digit Indian mobile number", () => {3  assert.equal(isValidPhone("9876543210"), true);4});5test("accepts +91 with spaces", () => {6  assert.equal(isValidPhone("+91 98765 43210"), true);7});8test("rejects numbers starting with 0 to 5", () => {9  assert.equal(isValidPhone("1234567890"), false);10});11 12// 2. GREEN: just enough code to pass all three13export function isValidPhone(input: string) {14  const digits = input.replace(/\s+/g, "").replace(/^\+91/, "");15  return /^[6-9]\d{9}$/.test(digits);16}

1/3Red: describe the first behaviour as a test, run it, and watch it fail.

In real TDD you'd add these tests one per cycle; they're shown together to save space. The node:test and assert imports are left out.

Save yourself the pain

Common mistakes

Oops

Writing all the tests at once, then all the code.

Do this instead

Go one test at a time: red, green, refactor. Small loops are the whole point.

Oops

Skipping the refactor step because the tests are green.

Do this instead

Green is exactly when it's safe to clean up. Skip it and TDD code gets as messy as any other.

Your mission

TDD a validator

~30 min

Quick check

In TDD, why should you see a new test fail before writing the code?

Go deeper

  1. 1Practice the red-green-refactor cycle on one small function.
  2. 2Notice how writing the test first changes how you design the function's interface.
  3. 3Try TDD on a real feature and reflect on whether it helped or slowed you down for that case.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge