Skip to content

Red-Green-Refactor Workflow

When to Use

Every time you implement a new feature or fix a bug using TDD. This is the core TDD workflow.

Steps

  1. RED - Write a Failing Test
  2. Think about the next small piece of behavior you need
  3. Write a test that describes that behavior
  4. Run the test and verify it fails for the right reason
  5. A test that passes without any implementation means your test is broken
// RED: Test for parsing a user's full name
describe('UserNameParser', () => {
  it('splits full name into first and last', () => {
    const parser = new UserNameParser();
    const result = parser.parse('John Doe');
    expect(result).toEqual({ first: 'John', last: 'Doe' });
  });
});
// Output: UserNameParser is not defined
  1. GREEN - Make the Test Pass (Quickly)
  2. Write the simplest code that makes the test pass
  3. Ignore code quality at this step - just make it work
  4. Hard-coding values is fine if it passes the test
  5. "Commit whatever sins necessary" - Kent Beck
// GREEN: Simplest implementation that passes
class UserNameParser {
  parse(fullName) {
    const parts = fullName.split(' ');
    return { first: parts[0], last: parts[1] };
  }
}
// Output: Test passes
  1. REFACTOR - Improve the Code
  2. Clean up duplication
  3. Improve names, structure, clarity
  4. Extract methods/functions if needed
  5. Tests must stay green throughout refactoring
  6. If a test fails during refactor, you broke something - undo and try again
// REFACTOR: Handle edge cases we realized during implementation
class UserNameParser {
  parse(fullName) {
    if (!fullName || typeof fullName !== 'string') {
      throw new Error('Invalid name');
    }
    const parts = fullName.trim().split(/\s+/); // Handle multiple spaces
    return {
      first: parts[0],
      last: parts.slice(1).join(' ')  // Handle middle names
    };
  }
}
// Wait - we just changed behavior without a test!
// This is wrong. Undo and write tests for edge cases first.
  1. Repeat - Add Next Test
  2. Once tests are green and code is clean, return to RED
  3. Write the next failing test for the next small behavior
  4. Repeat the cycle

Decision Points

At this step... If... Then...
RED Test passes without implementation Your test doesn't actually test new behavior - rewrite it
RED Test fails to compile That's fine - compilation failures are failures; move to GREEN
GREEN Implementation seems too simple/dumb That's fine - refactor will improve it, or next test will force better design
GREEN You're tempted to add extra features Stop - add only enough to pass this test; write another test for new features
REFACTOR A test fails You broke something - revert and refactor more carefully
REFACTOR Code smells obvious but fix requires new behavior Stop refactoring; write a new test for that behavior first

Common Mistakes

  • Skipping RED phase by writing code first - You lose the design benefit of thinking through behavior first
  • Writing complex tests that test multiple behaviors - Each test should verify one thing; break into multiple tests
  • Making tests pass with production changes instead of test fixes - If test is wrong, fix the test in RED phase
  • Spending too long on GREEN trying to write perfect code - Green phase is about speed; refactor is about quality
  • Forgetting to refactor - The most common mistake; leads to messy code despite test coverage
  • Refactoring without running tests - Always run tests after each small refactor step
  • Adding features during REFACTOR - Refactoring should only improve structure, never change behavior

See Also