# Tdd Workflow

> Test-Driven Development workflow with red-green-refactor pattern and best practices

- Skill: `lodetomasi/tdd-workflow` (Agent Skill)
- Install (CLI): `npx skillmds@latest add lodetomasi/tdd-workflow`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lodetomasi/tdd-workflow/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: lodetomasi (https://skillmd.com/u/lodetomasi)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/lodetomasi/tdd-workflow

---


# TDD Workflow Skill

## Overview
Test-Driven Development (TDD) skill implementing the red-green-refactor cycle, test-first development, and comprehensive testing strategies across multiple languages and frameworks.

## Capabilities

### 1. TDD Cycle Implementation
- **Red**: Write failing test first
- **Green**: Write minimal code to pass
- **Refactor**: Improve code while keeping tests green
- Test coverage tracking
- Continuous test execution

### 2. Testing Strategies
- Unit testing
- Integration testing
- End-to-end testing
- Test doubles (mocks, stubs, spies)
- Parameterized testing

### 3. Multi-Language Support
- **Python**: pytest, unittest
- **JavaScript**: Jest, Mocha, Vitest
- **Java**: JUnit, TestNG, Mockito
- **Go**: testing package
- **Ruby**: RSpec
- **.NET**: xUnit, NUnit

## TDD Principles

### The Three Laws of TDD
1. **Don't write production code** until you have a failing test
2. **Don't write more of a test** than is sufficient to fail
3. **Don't write more production code** than is sufficient to pass the test

### Red-Green-Refactor Cycle
```
1. RED: Write a failing test
   ↓
2. GREEN: Make it pass (simplest way)
   ↓
3. REFACTOR: Improve the code
   ↓
   Repeat
```

## Python TDD with pytest

### Setup
```bash
pip install pytest pytest-cov pytest-watch
```

### Example Workflow

**Step 1: RED - Write failing test**
```python
# test_calculator.py
import pytest
from calculator import Calculator

def test_add_two_numbers():
    calc = Calculator()
    result = calc.add(2, 3)
    assert result == 5  # This will fail - Calculator doesn't exist yet!
```

Run test:
```bash
pytest test_calculator.py
# ❌ FAIL: ModuleNotFoundError: No module named 'calculator'
```

**Step 2: GREEN - Make it pass**
```python
# calculator.py
class Calculator:
    def add(self, a, b):
        return a + b
```

Run test:
```bash
pytest test_calculator.py
# ✅ PASS: 1 passed
```

**Step 3: REFACTOR - Improve code**
```python
# calculator.py
class Calculator:
    def add(self, a: int, b: int) -> int:
        """Add two numbers and return the result."""
        return a + b
```

Run test again:
```bash
pytest test_calculator.py
# ✅ PASS: 1 passed (still works!)
```

### Advanced Testing

**Parameterized Tests**
```python
import pytest

@pytest.mark.parametrize("a,b,expected", [
    (2, 3, 5),
    (0, 0, 0),
    (-1, 1, 0),
    (100, 200, 300)
])
def test_add_multiple_cases(a, b, expected):
    calc = Calculator()
    assert calc.add(a, b) == expected
```

**Test Fixtures**
```python
@pytest.fixture
def calculator():
    return Calculator()

def test_add(calculator):
    assert calculator.add(2, 3) == 5

def test_subtract(calculator):
    assert calculator.subtract(5, 3) == 2
```

**Mocking**
```python
from unittest.mock import Mock, patch

def test_api_call():
    with patch('requests.get') as mock_get:
        mock_get.return_value.status_code = 200
        mock_get.return_value.json.return_value = {'data': 'test'}

        result = fetch_data('http://api.example.com')
        assert result == {'data': 'test'}
```

## JavaScript TDD with Jest

### Setup
```bash
npm install --save-dev jest @types/jest
```

### Example Workflow

**Step 1: RED**
```javascript
// calculator.test.js
const Calculator = require('./calculator');

describe('Calculator', () => {
  test('adds two numbers', () => {
    const calc = new Calculator();
    expect(calc.add(2, 3)).toBe(5);  // FAIL: Calculator not defined
  });
});
```

**Step 2: GREEN**
```javascript
// calculator.js
class Calculator {
  add(a, b) {
    return a + b;
  }
}

module.exports = Calculator;
```

**Step 3: REFACTOR**
```javascript
// calculator.js
class Calculator {
  /**
   * Adds two numbers
   * @param {number} a - First number
   * @param {number} b - Second number
   * @returns {number} Sum of a and b
   */
  add(a, b) {
    if (typeof a !== 'number' || typeof b !== 'number') {
      throw new TypeError('Both arguments must be numbers');
    }
    return a + b;
  }
}

module.exports = Calculator;
```

### Jest Features

**Test Coverage**
```bash
jest --coverage
```

**Watch Mode**
```bash
jest --watch
```

**Mocking**
```javascript
// Mock API call
jest.mock('./api');
const api = require('./api');

test('fetches data', async () => {
  api.fetchData.mockResolvedValue({ data: 'test' });
  const result = await getData();
  expect(result.data).toBe('test');
});
```

## Java TDD with JUnit 5

### Setup (Maven)
```xml
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>
```

### Example Workflow

**Step 1: RED**
```java
// CalculatorTest.java
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {
    @Test
    void testAdd() {
        Calculator calc = new Calculator();
        assertEquals(5, calc.add(2, 3));  // FAIL: Calculator not found
    }
}
```

**Step 2: GREEN**
```java
// Calculator.java
public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}
```

**Step 3: REFACTOR**
```java
// Calculator.java
public class Calculator {
    /**
     * Adds two integers
     * @param a first integer
     * @param b second integer
     * @return sum of a and b
     */
    public int add(int a, int b) {
        return Math.addExact(a, b);  // Throws on overflow
    }
}
```

### JUnit 5 Features

**Parameterized Tests**
```java
@ParameterizedTest
@CsvSource({
    "2, 3, 5",
    "0, 0, 0",
    "-1, 1, 0"
})
void testAddMultipleCases(int a, int b, int expected) {
    Calculator calc = new Calculator();
    assertEquals(expected, calc.add(a, b));
}
```

**Test Lifecycle**
```java
@BeforeEach
void setUp() {
    calc = new Calculator();
}

@AfterEach
void tearDown() {
    calc = null;
}
```

**Mockito Integration**
```java
@ExtendWith(MockitoExtension.class)
class ServiceTest {
    @Mock
    private Repository repository;

    @InjectMocks
    private Service service;

    @Test
    void testServiceMethod() {
        when(repository.findById(1)).thenReturn(Optional.of(entity));
        Result result = service.process(1);
        assertEquals("expected", result.getValue());
    }
}
```

## TDD Best Practices

### 1. Write Tests First
```
❌ BAD: Write code, then test
✅ GOOD: Write test, then code
```

### 2. Small Steps
```python
# Don't try to implement everything at once
def test_calculator():
    calc = Calculator()
    assert calc.add(2, 3) == 5  # Start simple
    # Later add more tests:
    # - multiply
    # - divide
    # - error handling
```

### 3. One Test at a Time
```
✅ Write one test
✅ Make it pass
✅ Refactor
❌ Don't write multiple failing tests
```

### 4. Test Behavior, Not Implementation
```python
# ❌ BAD: Testing implementation details
def test_uses_dictionary():
    cache = Cache()
    assert isinstance(cache._storage, dict)

# ✅ GOOD: Testing behavior
def test_stores_and_retrieves_value():
    cache = Cache()
    cache.set('key', 'value')
    assert cache.get('key') == 'value'
```

### 5. Fast Tests
```python
# ✅ Fast: In-memory operations
def test_calculation():
    result = calculate(2, 3)
    assert result == 5

# ❌ Slow: Database/network operations (use mocks)
def test_database():
    # Use test database or mock instead
    pass
```

## Test Coverage

### Aim for High Coverage
```bash
# Python
pytest --cov=src --cov-report=html

# JavaScript
jest --coverage

# Java
mvn test jacoco:report
```

### Coverage Guidelines
- **80-90%**: Good target for most projects
- **100%**: Not always necessary or practical
- **Focus**: Critical business logic > boilerplate

### Coverage Report Example
```
Name                Stmts   Miss  Cover
---------------------------------------
calculator.py          10      0   100%
database.py            50      5    90%
utils.py               20      8    60%
---------------------------------------
TOTAL                  80     13    84%
```

## Continuous Testing

### pytest-watch
```bash
# Auto-run tests on file changes
pytest-watch
```

### Jest watch mode
```bash
# Interactive test runner
jest --watch
```

### Gradle continuous testing
```bash
# Java continuous testing
gradle test --continuous
```

## Integration Scripts

### tdd_helper.sh
TDD workflow automation:
```bash
#!/bin/bash
# TDD workflow helper

ACTION=$1

case $ACTION in
  "red")
    echo "🔴 RED: Writing failing test..."
    echo "1. Write a test that fails"
    echo "2. Run: npm test / pytest / mvn test"
    ;;
  "green")
    echo "🟢 GREEN: Making test pass..."
    echo "1. Write minimal code to pass"
    echo "2. Run tests again"
    ;;
  "refactor")
    echo "🔵 REFACTOR: Improving code..."
    echo "1. Improve code quality"
    echo "2. Keep tests green"
    echo "3. Run tests continuously"
    ;;
  "watch")
    echo "👀 Starting watch mode..."
    if [ -f "package.json" ]; then
      jest --watch
    elif [ -f "pytest.ini" ] || [ -f "setup.py" ]; then
      pytest-watch
    else
      echo "No test framework detected"
    fi
    ;;
  *)
    echo "Usage: $0 {red|green|refactor|watch}"
    ;;
esac
```

### test_coverage_checker.py
Enforce coverage standards:
```python
#!/usr/bin/env python3
import json
import sys

def check_coverage(coverage_json, threshold=80):
    """Check if test coverage meets threshold"""
    with open(coverage_json) as f:
        data = json.load(f)

    total_coverage = data['totals']['percent_covered']

    print(f"Test Coverage: {total_coverage:.1f}%")

    if total_coverage < threshold:
        print(f"❌ FAIL: Coverage below {threshold}%")
        sys.exit(1)
    else:
        print(f"✅ PASS: Coverage meets {threshold}% threshold")
        sys.exit(0)

if __name__ == '__main__':
    check_coverage('coverage.json', threshold=80)
```

## Common TDD Patterns

### 1. Arrange-Act-Assert (AAA)
```python
def test_user_creation():
    # Arrange
    username = "testuser"
    email = "test@example.com"

    # Act
    user = User.create(username, email)

    # Assert
    assert user.username == username
    assert user.email == email
```

### 2. Given-When-Then (BDD style)
```javascript
describe('User Login', () => {
  it('should authenticate valid credentials', () => {
    // Given
    const user = createUser('john', 'password123');

    // When
    const result = authenticate('john', 'password123');

    // Then
    expect(result.success).toBe(true);
  });
});
```

### 3. Test Doubles
```python
# Dummy: Passed but never used
def test_with_dummy():
    dummy = DummyLogger()
    service = Service(dummy)

# Stub: Returns canned responses
def test_with_stub():
    stub = StubDatabase()
    stub.set_return_value([User('test')])

# Mock: Verifies interactions
def test_with_mock():
    mock = Mock()
    service.notify(mock)
    mock.send.assert_called_once()
```

## Requirements

```bash
# Python
pip install pytest pytest-cov pytest-watch pytest-mock

# JavaScript
npm install --save-dev jest @testing-library/react

# Java
# Add JUnit 5 + Mockito to Maven/Gradle

# Coverage tools
# Python: coverage.py (included with pytest-cov)
# JavaScript: built into Jest
# Java: JaCoCo
```

## Metrics to Track

- **Test coverage**: > 80%
- **Test execution time**: < 1 minute for unit tests
- **Test count**: Growing with features
- **Failure rate**: Quick to identify and fix
- **Refactoring safety**: Tests enable confident refactoring

