ReviseAlgo Logo

Testing JavaScript

Test-Driven Development (TDD)

Master Test-Driven Development in JavaScript. Learn the Red-Green-Refactor cycle, write tests before implementation, and design robust APIs.

Last Updated: July 15, 2026 10 min read

1. Introduction

Test-Driven Development (TDD) is a software development process where you write tests before writing the actual application code. It relies on a tight, repeating loop known as the Red-Green-Refactor cycle.

2. Why It Matters

Writing tests after writing code often leads to writing tests that match the implementation, rather than checking the requirements. TDD forces you to design clean APIs and write modular, testable code, preventing over-engineering by writing only the code required to pass the tests.

3. Real-World Analogy

Think of a Custom Brick Masonry Mould:

  • Code-First (Scribbling shape): You pour wet concrete on the ground and try to scrape it into a square shape before it dries. The edges are uneven, and the brick doesn't fit standard frames.
  • TDD (Setting the mould first): You assemble a rigid metal frame mould (the Test) matching the exact dimensions required. You pour the concrete (the Code) into the mould. The concrete fills the frame perfectly. Once it sets, you remove the frame mould and sand down the rough edges (Refactor), ensuring the brick fits the building structure.

4. The Red-Green-Refactor Cycle

TDD is structured around a three-step cycle:
1. 🔴 Red: Write an automated test for a feature before implementing it. Run the test and watch it fail (proving the test is valid and does not pass by accident).
2. 🟢 Green: Write the minimum amount of code required to make the test pass. Do not worry about code quality at this stage.
3. 🔵 Refactor: Clean up the code (remove duplication, improve variable naming, and optimize structure) while ensuring the tests remain green.

5. Practical Example

Let's walk through implementing a password strength checker using TDD:

Step 1: Write a failing test (RED)

Step 2: Write the minimum code to pass (GREEN)

Step 3: Clean up and refactor (REFACTOR)

We can now clean up variables or add performance optimizations knowing the test suite will instantly catch any regressions.

6. Common Mistakes

  • Writing too much code in the Green phase: Avoid writing optional helper methods or future features during the green phase. Write only the minimum code required to make the failing test pass. This prevents scope creep and keeps your codebase focused.

7. Quick Quiz

Q1: What is the primary focus of the 'Green' phase in the TDD loop?

A) To refactor code for performance optimization

B) To write the minimum code required to make the failing test pass

Answer: B — The Green phase focuses exclusively on making the test pass, leaving refactoring for the next phase.

8. Scenario-Based Challenge

The FizzBuzz TDD Implementation:

Implement a function fizzBuzz(n) using TDD: if n is divisible by 3, return "Fizz"; if divisible by 5, return "Buzz"; if divisible by both, return "FizzBuzz". Write the failing tests first, then write the code to make them pass sequentially.

9. Debugging Exercise

Explain why skipping the 'Red' phase can lead to testing errors:

// Requirement: check if a user is an adult (age >= 18)
// Developer writes code first:
function isAdult(user) {
  return true; // placeholder implementation
}

// Developer writes test, but skips running it failing first: test('checks if user is adult', () => { expect(isAdult({ age: 20 })).toBe(true); // Test passes! });

// Why is this a dangerous test verification?

View Solution

Diagnosis: The developer skipped the "Red" phase, meaning they never saw the test fail. The test passes for the wrong reason (because the function hardcodes true). If a user with age: 12 is passed, the function will still report true. Running the test in a failing state first (e.g. testing with a child user first) flags these placeholder implementation bugs.

Fix: Write a test case that expects false for children, run it, watch it fail, and then write the correct conditional logic to pass:

// Failing test (Red)
test('returns false for child', () => {
  expect(isAdult({ age: 10 })).toBe(false); // Fails first!
});

10. Interview Questions

🟢 Q1: Describe the Red-Green-Refactor cycle and explain its benefits.

Answer:
Red: Write a failing test for a new feature. This proves the test is valid and targets the correct requirement.
Green: Write the minimum code required to pass the test.
Refactor: Clean up and optimize the code while keeping the tests green.
Benefits:
1. Clean Code: Forces you to design modular, testable APIs before writing implementation details.
2. Safety Net: Prevents regression bugs when refactoring code.
3. Clear Scope: Prevents over-engineering by writing only the code required to make the tests pass.

11. Production Considerations

  • Watch Mode: When practicing TDD in production, run Jest in watch mode (jest --watch). Watch mode monitors your files and re-runs relevant tests automatically as you save changes, speeding up the feedback loop.