Workflow TDD

Le mode TDD (Test-Driven Development) d'ATOOX inverse le pipeline : les tests sont écrits AVANT le code.

Philosophie

┌─────────────────────────────────────────────────────────────┐
│                    CYCLE TDD                                 │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│     ┌─────────┐                                            │
│     │   RED   │ ← Écrire un test qui échoue                │
│     └────┬────┘                                            │
│          │                                                  │
│          ▼                                                  │
│     ┌─────────┐                                            │
│     │  GREEN  │ ← Écrire le code minimal qui passe         │
│     └────┬────┘                                            │
│          │                                                  │
│          ▼                                                  │
│     ┌──────────┐                                           │
│     │ REFACTOR │ ← Améliorer sans casser les tests         │
│     └────┬─────┘                                           │
│          │                                                  │
│          └──────────────────────────────────────────→ RED  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Lancer le mode TDD

/atoox --tdd "ajouter fonction de calcul de TVA"

Pipeline TDD

Le mode --tdd réordonne les steps :

Pipeline Standard :
  00c → 00 → 00-init → 00b → 01 → 02 → 03 → 04 → 05 → 06 → 07 → 08 → 09

Pipeline TDD :
  00c → 00 → 00-init → 00b → 01 → 02 → 07 ← (tests d'abord)
                                     ↓
                                    03 → 08 → 04 → 05 → 06 → 09

Exemple pratique

Étape 1 : Spécification

/atoox --tdd "calculer le prix TTC à partir du prix HT et du taux de TVA"

ATOOX clarifie :

Feature: TVA Calculator
Description: Calculate price including VAT from net price and VAT rate

Acceptance Criteria:
  - Calculate TTC = HT × (1 + TVA/100)
  - Handle standard rates: 20%, 10%, 5.5%, 2.1%
  - Round to 2 decimal places
  - Throw error for negative prices
  - Throw error for invalid VAT rates

Étape 2 : Tests d'abord (RED)

ATOOX écrit les tests AVANT le code :

// src/lib/tva.test.ts
import { describe, it, expect } from 'vitest';
import { calculateTTC } from './tva';

describe('calculateTTC', () => {
  // Happy path
  it('should calculate TTC with 20% VAT', () => {
    expect(calculateTTC(100, 20)).toBe(120);
  });

  it('should calculate TTC with 5.5% VAT', () => {
    expect(calculateTTC(100, 5.5)).toBe(105.5);
  });

  it('should round to 2 decimal places', () => {
    expect(calculateTTC(99.99, 20)).toBe(119.99);
  });

  // Edge cases
  it('should handle zero price', () => {
    expect(calculateTTC(0, 20)).toBe(0);
  });

  it('should handle zero VAT', () => {
    expect(calculateTTC(100, 0)).toBe(100);
  });

  // Error cases
  it('should throw for negative price', () => {
    expect(() => calculateTTC(-100, 20)).toThrow('Le prix doit être positif');
  });

  it('should throw for negative VAT', () => {
    expect(() => calculateTTC(100, -5)).toThrow('Le taux de TVA doit être positif');
  });

  it('should throw for VAT > 100', () => {
    expect(() => calculateTTC(100, 150)).toThrow('Le taux de TVA ne peut pas dépasser 100%');
  });
});

Exécution des tests :

Running tests...

  ✗ calculateTTC › should calculate TTC with 20% VAT
    Error: calculateTTC is not a function

  ✗ 8 tests failed

RED phase complete ✓

Étape 3 : Code minimal (GREEN)

ATOOX écrit le code pour faire passer les tests :

// src/lib/tva.ts
export function calculateTTC(priceHT: number, vatRate: number): number {
  // Guard clauses
  if (priceHT < 0) {
    throw new Error('Le prix doit être positif');
  }

  if (vatRate < 0) {
    throw new Error('Le taux de TVA doit être positif');
  }

  if (vatRate > 100) {
    throw new Error('Le taux de TVA ne peut pas dépasser 100%');
  }

  // Calculation
  const priceTTC = priceHT * (1 + vatRate / 100);

  // Round to 2 decimal places
  return Math.round(priceTTC * 100) / 100;
}

Exécution des tests :

Running tests...

  ✓ calculateTTC › should calculate TTC with 20% VAT
  ✓ calculateTTC › should calculate TTC with 5.5% VAT
  ✓ calculateTTC › should round to 2 decimal places
  ✓ calculateTTC › should handle zero price
  ✓ calculateTTC › should handle zero VAT
  ✓ calculateTTC › should throw for negative price
  ✓ calculateTTC › should throw for negative VAT
  ✓ calculateTTC › should throw for VAT > 100

  8 tests passed

GREEN phase complete ✓

Étape 4 : Refactoring

ATOOX propose des améliorations :

// src/lib/tva.ts (refactorisé)

/** Standard French VAT rates */
export const VAT_RATES = {
  STANDARD: 20,
  INTERMEDIATE: 10,
  REDUCED: 5.5,
  SUPER_REDUCED: 2.1,
} as const;

export type VATRate = typeof VAT_RATES[keyof typeof VAT_RATES];

/**
 * Calculate price including VAT (TTC) from net price (HT)
 *
 * @param priceHT - Net price without VAT
 * @param vatRate - VAT rate as percentage (e.g., 20 for 20%)
 * @returns Price including VAT, rounded to 2 decimal places
 * @throws Error if price is negative
 * @throws Error if VAT rate is invalid
 */
export function calculateTTC(priceHT: number, vatRate: number): number {
  validateInputs(priceHT, vatRate);
  return roundToDecimals(priceHT * (1 + vatRate / 100), 2);
}

function validateInputs(price: number, rate: number): void {
  if (price < 0) {
    throw new Error('Le prix doit être positif');
  }
  if (rate < 0) {
    throw new Error('Le taux de TVA doit être positif');
  }
  if (rate > 100) {
    throw new Error('Le taux de TVA ne peut pas dépasser 100%');
  }
}

function roundToDecimals(value: number, decimals: number): number {
  const factor = Math.pow(10, decimals);
  return Math.round(value * factor) / factor;
}

Re-exécution des tests :

  8 tests passed

REFACTOR phase complete ✓
Tests still green after refactoring

Avantages du mode TDD

Aspect Bénéfice
Clarté Les tests définissent le comportement attendu
Confiance Chaque ligne de code est couverte
Design Le code est naturellement testable
Documentation Les tests servent de documentation vivante
Régression Détection immédiate des bugs

Combinaisons utiles

# TDD + Full Quality
/atoox --tdd --full "implémenter panier d'achat"

# TDD + Pair Programming
/atoox --tdd --pair "ajouter système de notation"

# TDD + Security Audit
/atoox --tdd --security "implémenter authentification"

Bonnes pratiques

1. Un test à la fois

Ne pas écrire tous les tests d'un coup. Cycle : 1 test → code → refactor → prochain test.

2. Tests expressifs

// ❌ Mauvais
it('test1', () => {
  expect(fn(100, 20)).toBe(120);
});

// ✅ Bon
it('should calculate TTC with 20% VAT', () => {
  const netPrice = 100;
  const vatRate = 20;
  const expectedTTC = 120;

  expect(calculateTTC(netPrice, vatRate)).toBe(expectedTTC);
});

3. Arrange-Act-Assert

it('should apply discount before VAT', () => {
  // Arrange
  const netPrice = 100;
  const discount = 10;
  const vatRate = 20;

  // Act
  const result = calculateDiscountedTTC(netPrice, discount, vatRate);

  // Assert
  expect(result).toBe(108); // (100 - 10) × 1.20
});

4. Edge cases d'abord

Les cas limites révèlent souvent des bugs de design :

describe('edge cases', () => {
  it('should handle zero', () => {});
  it('should handle negative', () => {});
  it('should handle very large numbers', () => {});
  it('should handle decimals', () => {});
  it('should handle null/undefined', () => {});
});

Prochaines étapes