# Démarrer une extension WordPress en TDD, un cycle red-green-refactor à la fois

> Écrire le test avant le code change la façon de concevoir une extension. Voici comment mener un premier cycle red-green-refactor sur une fonctionnalité simple.

- Auteur : WordPress Développement
- Publié le : 2020-01-08
- Mis à jour le : 2020-01-08
- Catégorie : Tests
- URL : https://www.wpmoderne.fr/tests/tdd-extension-wordpress-cycle-red-green-refactor/

## L’essentiel

- Écrire le test qui échoue avant toute ligne de code
- Coder le minimum pour le faire passer au vert
- Refactoriser seulement une fois le test vert

`phpunit --filter test_calcule_remise` : voilà la première commande qui compte dans une séance de développement piloté par les tests. Elle échoue, forcément, puisque rien n'existe encore. C'est exactement le point de départ recherché.

Le TDD (Test-Driven Development) inverse l'ordre habituel : au lieu d'écrire une fonction puis de vérifier qu'elle marche, on décrit d'abord le comportement attendu sous forme de test, puis on code jusqu'à ce que ce test passe. Sur une extension WordPress qui calcule une remise fidélité, ce billet déroule un premier cycle complet, sans entrer dans le choix d'un framework de tests ni dans la question de la couverture de code : ces sujets méritent chacun leur propre traitement.

## Rouge : écrire le test qui n'a aucune chance de passer

Le point de départ est une classe qui n'existe pas encore, `Fidelite_Calculateur`. Le test décrit ce qu'elle doit faire, pas comment :

```
class Test_Fidelite_Calculateur extends WP_UnitTestCase {

    public function test_calcule_remise_pour_client_fidele() {
        $calculateur = new Fidelite_Calculateur();
        $remise = $calculateur->calculer( 12, 150.00 );

        $this->assertSame( 15.00, $remise );
    }
}
```

Lancer `phpunit` à ce stade renvoie une erreur de classe introuvable. C'est le rouge attendu, et c'est un rouge utile : il confirme que le test est bien exécuté et qu'il échoue pour la bonne raison, pas à cause d'une faute de frappe dans le nom de la méthode.

1. Créer le fichier de test avant tout fichier de production.
2. Nommer la méthode de test d'après le comportement, pas d'après l'implémentation.
3. Lancer la suite et vérifier que l'échec correspond bien à « classe absente », pas à une erreur de syntaxe.

## Vert : coder le strict minimum, rien de plus

La tentation est grande d'anticiper d'autres cas : remise dégressive, plafond, exceptions saisonnières. Le TDD demande de résister et d'écrire uniquement ce qui fait passer le test présent :

```
class Fidelite_Calculateur {

    public function calculer( int $mois_anciennete, float $montant ) {
        return round( $montant * 0.10, 2 );
    }
}
```

> L'essentiel à retenir : Écrire le test qui échoue avant toute ligne de code ; Coder le minimum pour le faire passer au vert ; Refactoriser seulement une fois le test vert

Ce code est volontairement simpliste : il ignore `$mois_anciennete`, ce qui semble absurde à premier vue. C'est pourtant la bonne étape. Le test suivant, sur un client depuis trois mois seulement, viendra forcer l'ajout de la logique de seuil. Chaque règle métier arrive donc portée par un test qui l'exige, jamais par anticipation.

## Refactor : nettoyer sans changer le comportement observable

Une fois le test vert, et seulement à ce moment, vient le refactoring. La règle est stricte : le comportement visible par les tests ne doit pas bouger d'un iota pendant cette phase. On peut renommer une variable, extraire une constante, simplifier une expression :

```
class Fidelite_Calculateur {

    private const TAUX_REMISE = 0.10;

    public function calculer( int $mois_anciennete, float $montant ) {
        return round( $montant * self::TAUX_REMISE, 2 );
    }
}
```

Relancer la suite entière après chaque petite modification confirme qu'aucune régression ne s'est glissée. C'est cette relance systématique, et non la relecture visuelle du code, qui donne la confiance nécessaire pour continuer à toucher au fichier.

## Enchaîner les cycles jusqu'à la fonctionnalité complète

Le second cycle ajoute le cas du client récent :

```
public function test_pas_de_remise_avant_six_mois() {
    $calculateur = new Fidelite_Calculateur();
    $remise = $calculateur->calculer( 3, 150.00 );

    $this->assertSame( 0.00, $remise );
}
```

Ce test échoue immédiatement, puisque la classe actuelle ignore l'ancienneté. Il force à écrire une condition, et seulement celle-là :

```
public function calculer( int $mois_anciennete, float $montant ) {
    if ( $mois_anciennete < 6 ) {
        return 0.00;
    }

    return round( $montant * self::TAUX_REMISE, 2 );
}
```

Un troisième cycle viendrait couvrir le palier à douze mois, un quatrième le plafond de remise. Chaque règle nouvelle suit exactement la même mécanique : un test qui échoue, un code minimal qui la satisfait, un nettoyage qui ne casse rien.

## Ce que cette discipline empêche concrètement

Sur une extension WordPress, le TDD évite en particulier deux pièges fréquents :

- Écrire une fonction généraliste avant de savoir quels cas réels elle doit couvrir, ce qui produit souvent du code mort.
- Découvrir un bug de calcul six mois après la mise en production, faute d'avoir formalisé le comportement attendu dès le départ.

> Un cycle qui dure plus de quelques minutes cache presque toujours un test trop ambitieux : mieux vaut le découper en deux cycles plus modestes.

La difficulté, au tout début, n'est pas technique mais mentale : il faut accepter d'écrire un code qui échoue, de le voir échouer, et de résister à l'envie de tout résoudre d'un coup. Cette discipline paie surtout sur les fonctions à règles métier, comme les calculs de remise, de quota ou de taxe, où chaque cas limite mérite son propre aller-retour rouge-vert-refactor.

## En résumé

Un cycle TDD tient en trois gestes répétés : un test qui échoue pour la bonne raison, un code minimal qui le fait réussir, un nettoyage qui préserve ce résultat. Appliqué fonction par fonction sur une extension WordPress, ce rythme construit une suite de tests qui documente le comportement réel du code, sans jamais avoir eu besoin de l'écrire après coup.
