# Data providers PHPUnit pour couvrir les variantes de WP_Query

> Douze requêtes similaires, douze méthodes de test presque identiques ? Un fournisseur de données unique permet de tout couvrir sans dupliquer une ligne.

- Auteur : Clément Hadrot
- Publié le : 2020-09-12
- Mis à jour le : 2020-09-12
- Catégorie : Tests
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tests/data-providers-phpunit-variantes-wp-query/

## L’essentiel

- Un tableau de scénarios, une seule méthode de test
- Nommer chaque cas pour un rapport lisible
- Combiner plusieurs providers pour multiplier les axes

Une extension d'annuaire professionnel que nous maintenons propose un filtrage par catégorie, par ville et par statut d'adhésion. Combinés, ces trois filtres produisent des dizaines de variantes de `WP_Query` à vérifier : catégorie seule, ville seule, les deux ensemble, avec ou sans adhérent actif, etc. La première version de la suite comptait quatorze méthodes de test, presque toutes identiques à trois lignes près. Un fournisseur de données a permis de tout ramener à une seule méthode.

Le data provider PHPUnit répond exactement à ce besoin : dérouler un même scénario de test sur un ensemble de jeux de données, sans dupliquer la logique d'assertion.

## Étape 1 — Identifier le squelette de test répété

Avant d'écrire le provider, il faut repérer ce qui varie réellement entre les méthodes existantes. Dans notre cas : les arguments passés à `WP_Query`, et le nombre de résultats attendus. Le reste — création des fixtures, appel à la requête, assertion sur le compte — était strictement identique.

```
public function test_filtre_categorie_seule(): void {
    $requete = new WP_Query(['post_type' => 'membre', 'tax_query' => [...]]);
    $this->assertCount(3, $requete->posts);
}

public function test_filtre_ville_seule(): void {
    $requete = new WP_Query(['post_type' => 'membre', 'meta_query' => [...]]);
    $this->assertCount(5, $requete->posts);
}
```

## Étape 2 — Écrire le fournisseur de données

Un data provider est une méthode qui retourne un tableau de tableaux, chaque sous-tableau correspondant aux arguments d'un appel de la méthode de test. Depuis PHPUnit 9, on peut aussi utiliser des clés textuelles pour nommer chaque cas dans le rapport :

```
public static function scenarios_filtrage(): array {
    return [
        'categorie seule'            => ['args' => ['tax_query' => [['taxonomy' => 'secteur', 'terms' => 'photographie']]], 'attendu' => 3],
        'ville seule'                => ['args' => ['meta_query' => [['key' => 'ville', 'value' => 'Lyon']]], 'attendu' => 5],
        'categorie et ville'         => ['args' => ['tax_query' => [['taxonomy' => 'secteur', 'terms' => 'photographie']], 'meta_query' => [['key' => 'ville', 'value' => 'Lyon']]], 'attendu' => 1],
        'aucun filtre'               => ['args' => [], 'attendu' => 9],
        'ville inexistante'          => ['args' => ['meta_query' => [['key' => 'ville', 'value' => 'Atlantide']]], 'attendu' => 0],
    ];
}
```

## Étape 3 — Brancher le provider sur la méthode de test

Depuis PHPUnit 10, l'attribut `#[DataProvider]` remplace l'annotation `@dataProvider` historique, mais les deux syntaxes cohabitent selon la version du projet :

```
#[DataProvider('scenarios_filtrage')]
public function test_filtrage_annuaire(array $args, int $attendu): void {
    $requete = new WP_Query(array_merge(['post_type' => 'membre'], $args));
    $this->assertCount($attendu, $requete->posts);
}
```

> L'essentiel à retenir : Un tableau de scénarios, une seule méthode de test ; Nommer chaque cas pour un rapport lisible ; Combiner plusieurs providers pour multiplier les axes

Chaque entrée du tableau devient une exécution indépendante de `test_filtrage_annuaire`, avec son propre statut dans le rapport — un échec sur « ville et categorie » n'affecte pas les quatre autres cas, et le rapport nomme précisément lequel a échoué.

## Étape 4 — Préparer les fixtures une seule fois

Le provider ne doit fournir que des données statiques (arguments et résultats attendus), jamais créer de contenu en base — il est exécuté avant même l'initialisation de WordPress dans certains contextes. Les fixtures correspondantes se créent donc classiquement dans `setUp()`, de façon à couvrir tous les cas du provider avec un seul jeu de données cohérent :

```
protected function setUp(): void {
    parent::setUp();
    $this->factory()->post->create(['post_type' => 'membre', 'meta_input' => ['ville' => 'Lyon']]);
    // ... création des huit autres membres avec combinaisons ville/catégorie/statut
}
```

## Combiner plusieurs providers pour multiplier les axes

Quand deux dimensions indépendantes doivent être croisées — par exemple le filtrage et le rôle de l'utilisateur qui exécute la requête — il est tentant d'ajouter un second `#[DataProvider]`. PHPUnit ne les combine pas automatiquement en produit cartésien : il faut le faire soi-même dans un seul provider, ou accepter deux méthodes de test distinctes si la logique diffère réellement selon le rôle :

- Un provider unique reste préférable tant que la logique testée est identique quel que soit l'axe.
- Deux providers séparés se justifient si les assertions elles-mêmes diffèrent selon l'axe testé.
- Un tableau généré dynamiquement (boucle imbriquée dans le provider) évite d'écrire à la main un produit cartésien de dix lignes.

> Un data provider bien nommé documente à lui seul les règles métier du filtrage — nul besoin d'aller lire le code de l'extension pour comprendre ce qu'elle est censée faire.

## En résumé

Les data providers ne réduisent pas seulement la duplication : ils rendent explicite la matrice de scénarios qu'un développeur doit avoir en tête en modifiant la logique de filtrage. Sur l'annuaire professionnel, faire passer quatorze méthodes à une seule a aussi eu un effet secondaire appréciable — ajouter un nouveau scénario de filtrage ne demande plus qu'une ligne dans le tableau, jamais une nouvelle méthode complète à écrire et maintenir.
