stackademic

The leading education platform for anyone with an interest in software development.

Test-Driven Development

Writing a failing test first, then the code that makes it pass

Overview

Test-Driven Development (TDD) flips the usual order: you write a test before the code it checks. The rhythm is Red, Green, Refactor — write a failing test (red), write just enough code to pass it (green), then clean up the code while tests stay green. This keeps designs simple and guarantees every line is covered by a test.

Syntax / Usage

Start with a test for behavior that doesn't exist yet. It fails because the function isn't written, which proves the test is real.

// Step 1 (Red): write the test first
const { slugify } = require("./slugify");

test("converts a title to a url slug", () => {
  expect(slugify("Hello World")).toBe("hello-world");
});
// Step 2 (Green): minimal code to pass
function slugify(text) {
  return text.toLowerCase().replace(/\s+/g, "-");
}
module.exports = { slugify };

Run the test after each step. Only refactor once it is green.

Examples

Adding a new requirement by writing the next failing test:

test("removes punctuation", () => {
  expect(slugify("Hello, World!")).toBe("hello-world");
});
// Step 3 (Refactor): extend code to satisfy the new test
function slugify(text) {
  return text
    .toLowerCase()
    .replace(/[^\w\s]/g, "")
    .trim()
    .replace(/\s+/g, "-");
}
module.exports = { slugify };

Common Mistakes

  • Writing the implementation first, then backfilling tests, which isn't TDD
  • Writing a huge test that forces you to build everything at once
  • Skipping the refactor step, leaving messy code behind passing tests
  • Not watching the test fail first, so a broken test can silently pass
  • Testing internal helpers instead of the behavior you actually want

See Also

testing-unit-tests testing-fundamentals testing-mocking