# Un data provider PHPUnit rejoue un test avec dix jeux de données

> Couvrir dix variantes d'un même calcul sans dupliquer une seule méthode de test : la mécanique d'un data provider PHPUnit expliquée pas à pas, sur un cas réel.

- Auteur : Clément Hadrot
- Publié le : 2025-09-18
- Mis à jour le : 2025-09-18
- Catégorie : Tests
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tests/data-provider-phpunit-dix-jeux-de-donnees/

## L’essentiel

- Un data provider exécute la même méthode de test une fois par jeu de données fourni
- Chaque jeu de données porte un nom explicite, visible dans le rapport d'échec
- Un seul échec parmi dix jeux n'invalide pas les neuf autres, chacun reste indépendant

`#[DataProvider('fournirLesCas')]` : cet attribut, placé au-dessus d'une méthode de test PHPUnit, suffit à la transformer en test paramétré, exécuté une fois pour chaque jeu de données retourné par la méthode fournisseuse. Ce mécanisme évite d'écrire dix méthodes de test presque identiques pour vérifier une même fonction de calcul de remise, appliquée à des montants de commande différents.

Le cas retenu ici concerne une fonction qui calcule une remise progressive sur un abonnement de location de matériel événementiel, avec des paliers différents selon la durée de location. Sans data provider, chaque palier aurait nécessité sa propre méthode de test, dupliquant à chaque fois la structure d'appel et d'assertion.

## Étape 1 : identifier la fonction à couvrir

La fonction testée calcule une remise en pourcentage selon le nombre de jours de location, avec quatre paliers distincts et des cas limites à chaque frontière :

```
function wpm_calculer_remise_location(int $jours): float
{
    return match (true) {
        $jours >= 30 => 0.20,
        $jours >= 14 => 0.12,
        $jours >= 7  => 0.05,
        default     => 0.0,
    };
}
```

## Étape 2 : écrire la méthode fournisseuse de données

> L'essentiel à retenir : Un data provider exécute la même méthode de test une fois par jeu de données fourni ; Chaque jeu de données porte un nom explicite, visible dans le rapport d'échec ; Un seul échec parmi dix jeux n'invalide pas les neuf autres, chacun reste indépendant

La méthode fournisseuse retourne un tableau associatif, où chaque clé nomme explicitement le cas couvert, et chaque valeur contient les arguments à transmettre à la méthode de test :

```
public static function fournirLesCas(): array
{
    return [
        'aucune remise sous 7 jours' => [6, 0.0],
        'frontière basse à 7 jours' => [7, 0.05],
        'palier intermédiaire à 10 jours' => [10, 0.05],
        'frontière à 14 jours' => [14, 0.12],
        'palier intermédiaire à 20 jours' => [20, 0.12],
        'frontière haute à 30 jours' => [30, 0.20],
        'longue durée à 90 jours' => [90, 0.20],
        'un jour seulement' => [1, 0.0],
        'zéro jour, cas limite' => [0, 0.0],
        'juste avant la frontière de 14 jours' => [13, 0.05],
    ];
}
```

## Étape 3 : brancher le data provider sur la méthode de test

L'attribut `#[DataProvider]`, introduit avec les attributs PHP 8 et la syntaxe moderne de PHPUnit, remplace l'ancienne annotation `@dataProvider` en commentaire, tout en produisant le même comportement d'exécution répétée :

```
use PHPUnit\Framework\Attributes\DataProvider;

final class RemiseLocationTest extends \PHPUnit\Framework\TestCase
{
    #[DataProvider('fournirLesCas')]
    public function testCalculRemiseSelonDureeLocation(int $jours, float $attendu): void
    {
        $this->assertSame($attendu, wpm_calculer_remise_location($jours));
    }

    public static function fournirLesCas(): array
    {
        // contenu vu à l'étape 2
        return [];
    }
}
```

### Ce qu'affiche le rapport en cas d'échec

Si le cas nommé « frontière à 14 jours » échoue, le rapport PHPUnit affiche explicitement ce nom dans le résumé des échecs, plutôt qu'un simple numéro d'itération anonyme. Cette lisibilité justifie à elle seule de nommer chaque clé du tableau retourné, plutôt que de se contenter d'un tableau indexé numériquement.

## Étape 4 : vérifier l'indépendance des cas

Chacune des dix exécutions constitue un test PHPUnit distinct dans le rapport final, avec son propre statut de réussite ou d'échec. Un échec sur le cas « zéro jour » n'empêche aucun des neuf autres cas de s'exécuter normalement, contrairement à une boucle manuelle avec plusieurs assertions dans une seule méthode, où la première assertion en échec interromprait l'exécution des suivantes.

## Étape 5 : éviter le piège du data provider trop générique

Un data provider qui retourne des centaines de combinaisons générées automatiquement, par exemple via une double boucle sur toutes les valeurs possibles de jours et de paliers, produit un rapport illisible en cas d'échec multiple, et ralentit la suite sans gain de couverture proportionnel. La règle retenue ici limite chaque data provider à des cas choisis manuellement pour leur pertinence, en particulier les frontières de chaque palier, plutôt qu'à une génération exhaustive et indifférenciée.

Cette limite volontaire distingue également le data provider PHPUnit d'un outil de test basé sur les propriétés, comme Eris, qui génère lui-même des centaines de valeurs aléatoires pour chercher un cas en échec. Les deux approches restent complémentaires plutôt que concurrentes : le data provider documente des cas connus et significatifs, l'outil de propriétés explore un espace plus large à la recherche de cas non anticipés.

## En résumé

Un data provider PHPUnit transforme une méthode de test unique en dix vérifications indépendantes, chacune nommée explicitement, sans dupliquer la structure d'appel ni l'assertion. Sur ce calcul de remise à quatre paliers, cette approche a permis de couvrir systématiquement chaque frontière de palier, y compris les cas limites les plus faciles à oublier en écrivant des tests un par un, tout en gardant un rapport d'échec lisible grâce au nommage explicite de chaque jeu de données.
