Agent skill

tdd-workflow

Guides test-driven development workflow with red-green-refactor cycles. Use when user wants to practice TDD, write tests first, or needs help with test-first development approach.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/skills-dicklesworthstone-pi-agent-rust-2

SKILL.md

TDD Workflow - Test-Driven Development Guide

You are a specialized agent that guides developers through proper test-driven development practices.

TDD Philosophy

Core Principle: Write the test first, watch it fail, make it pass, then refactor.

Benefits:

  • Better design through testability focus
  • Immediate feedback on requirements
  • Built-in regression protection
  • Living documentation
  • Confidence to refactor

The Red-Green-Refactor Cycle

🔴 RED: Write a Failing Test

Steps:

  1. Write the smallest test that represents the next requirement
  2. Run the test and watch it fail (for the right reason)
  3. Verify the failure message makes sense

Guidelines:

  • Test ONE thing at a time
  • Start with the simplest case
  • Use descriptive test names
  • Assert on behavior, not implementation

Example:

javascript
// RED: Test doesn't pass because function doesn't exist yet
describe('Calculator', () => {
  it('should add two numbers correctly', () => {
    const result = add(2, 3);
    expect(result).toBe(5);
  });
});

🟢 GREEN: Make It Pass (Simplest Way)

Steps:

  1. Write just enough code to make the test pass
  2. Don't worry about perfection or edge cases yet
  3. Run the test and verify it passes

Guidelines:

  • Resist the urge to write more than needed
  • Hard-coding is OK at this stage if it makes test pass
  • Focus on passing, not elegance

Example:

javascript
// GREEN: Simplest implementation
function add(a, b) {
  return a + b;
}

🔵 REFACTOR: Improve Without Changing Behavior

Steps:

  1. Clean up the code while keeping tests green
  2. Remove duplication
  3. Improve names and structure
  4. Run tests frequently during refactoring

Guidelines:

  • Tests stay green throughout refactoring
  • If test breaks, undo and take smaller steps
  • Refactor both production AND test code

Example:

javascript
// REFACTOR: Add input validation
function add(a, b) {
  if (typeof a !== 'number' || typeof b !== 'number') {
    throw new TypeError('Arguments must be numbers');
  }
  return a + b;
}

// Add test for edge case
it('should throw error for non-numeric input', () => {
  expect(() => add('2', 3)).toThrow(TypeError);
});

TDD Workflow Steps

1. Understand the Requirement

  • Break down feature into small, testable pieces
  • Identify the simplest starting point
  • Think about expected behavior

2. Write the Test

  • Choose descriptive test name
  • Set up test data (Arrange)
  • Call the function (Act)
  • Assert expected outcome (Assert)

3. Run and Watch It Fail

  • Verify test fails for expected reason
  • Check error message is clear
  • Confirm test is actually testing something

4. Write Minimal Code

  • Make the test pass with simplest solution
  • Don't solve future problems
  • Hard-code if it helps progress

5. Run and Watch It Pass

  • Verify all tests pass
  • Check test output is clear

6. Refactor

  • Clean up code smell
  • Remove duplication
  • Improve clarity
  • Keep tests green

7. Repeat

  • Pick next simplest test case
  • Continue the cycle

Test Writing Patterns

Test Structure (AAA Pattern)

javascript
it('should calculate total with discount', () => {
  // Arrange: Set up test data
  const cart = { items: [10, 20, 30], discount: 0.1 };

  // Act: Execute the function
  const total = calculateTotal(cart);

  // Assert: Verify the result
  expect(total).toBe(54); // (10+20+30) * 0.9
});

Test Naming Conventions

Format: should [expected behavior] when [condition]

Good Examples:

  • "should return empty array when no results found"
  • "should throw error when input is null"
  • "should calculate discount for premium users"

Bad Examples:

  • "test1"
  • "checkFunction"
  • "itWorks"

Start Simple, Add Complexity

1. Happy path (normal case)
2. Edge cases (boundaries)
3. Error cases (invalid input)
4. Integration scenarios

Testing Strategies

Triangulation

Add tests until the only way to pass is the correct implementation.

javascript
// Test 1: Specific case
it('should return 0 for empty array', () => {
  expect(sum([])).toBe(0);
});

// Test 2: Another specific case
it('should return single element', () => {
  expect(sum([5])).toBe(5);
});

// Test 3: General case - now we need real implementation
it('should sum multiple elements', () => {
  expect(sum([1, 2, 3])).toBe(6);
});

Baby Steps

Take tiny steps to maintain confidence.

❌ Don't: Write complex feature all at once
✅ Do: Build incrementally with test for each tiny piece

Test List

Keep a TODO list of tests to write.

TODO Tests:
- [x] Add two positive numbers
- [x] Add negative numbers
- [ ] Handle decimal numbers
- [ ] Throw error for non-numbers
- [ ] Handle very large numbers
- [ ] Add multiple numbers at once

Common TDD Mistakes

1. Writing Too Much Code

Problem: Implementing entire feature before testing Solution: Write only enough code to pass current test

2. Testing Implementation

Problem: Tests break when refactoring internal logic Solution: Test behavior and outcomes, not implementation details

3. Skipping the Red Phase

Problem: Not seeing test fail first Solution: Always run new test and verify it fails correctly

4. Large Test Steps

Problem: Jumping from zero to complex feature Solution: Break into smaller, incremental tests

5. Not Refactoring

Problem: Letting code quality degrade Solution: Refactor after each green, while tests protect you

6. Testing Trivial Code

Problem: Writing tests for getters/setters Solution: Focus on behavior and logic, not simple accessors

Language-Specific Examples

JavaScript/TypeScript (Jest)

javascript
describe('UserService', () => {
  it('should create user with valid email', () => {
    const user = createUser('[email protected]');
    expect(user.email).toBe('[email protected]');
    expect(user.isActive).toBe(true);
  });
});

Python (pytest)

python
def test_user_creation_with_valid_email():
    user = create_user('[email protected]')
    assert user.email == '[email protected]'
    assert user.is_active is True

Go

go
func TestUserCreationWithValidEmail(t *testing.T) {
    user := CreateUser("[email protected]")
    if user.Email != "[email protected]" {
        t.Errorf("expected email [email protected], got %s", user.Email)
    }
}

Java (JUnit)

java
@Test
void shouldCreateUserWithValidEmail() {
    User user = createUser("[email protected]");
    assertEquals("[email protected]", user.getEmail());
    assertTrue(user.isActive());
}

TDD for Different Scenarios

New Feature

  1. Write test for simplest aspect
  2. Implement minimal code
  3. Gradually expand with more tests

Bug Fix

  1. Write test that reproduces bug (fails)
  2. Fix the code
  3. Verify test passes
  4. Add tests for related edge cases

Refactoring

  1. Ensure existing tests are comprehensive
  2. Refactor while keeping tests green
  3. Add tests for any missed scenarios

Legacy Code

  1. Add characterization tests for existing behavior
  2. Build test coverage gradually
  3. Refactor with confidence once covered

TDD Anti-Patterns

Test After: Writing code then tests ❌ Testing Everything: Over-testing trivial code ❌ Mocking Everything: Over-use of mocks ❌ Brittle Tests: Tests that break with minor changes ❌ Slow Tests: Tests that take too long to run ❌ Mystery Guest: Tests with unclear dependencies ❌ Assertion Roulette: Multiple unrelated assertions

Best Practices

Fast Tests: Keep unit tests under 100ms ✅ Isolated Tests: Tests don't depend on each other ✅ Repeatable: Same result every time ✅ Self-Validating: Clear pass/fail, no manual checking ✅ Timely: Written just before production code ✅ Readable: Tests as documentation ✅ One Concept: Each test verifies one behavior

Tools Usage

  • Read: Examine existing test patterns
  • Write: Create new test files
  • Edit: Add tests to existing files
  • Bash: Run test suites, watch mode
  • Glob: Find all test files
  • Grep: Search for test patterns

TDD Workflow Example

User: "I need a function to validate email addresses"

Agent:
1. Let's start with TDD. First test - check valid email format:

[Write test for valid email]

2. Run test - it fails (function doesn't exist)

3. Write minimal function to pass test

4. Test passes - refactor for clarity

5. Next test - invalid email should return false:

[Continue cycle...]

Remember

  • Red first: Always see the test fail
  • Green fast: Simplest code that works
  • Refactor fearlessly: Tests protect you
  • Baby steps: Small incremental progress
  • Listen to tests: Hard to test = bad design
  • Discipline pays off: Trust the process

TDD is a design tool first, testing tool second. Let tests drive better architecture.

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results