# Tests unitaires ou tests d’intégration WordPress : lequel écrire et quand

> Différence concrète entre les deux approches dans l'écosystème WordPress, coût de mise en place, vitesse d'exécution et exemples de code pour chaque cas.

- Auteur : Clément Hadrot
- Publié le : 2020-11-19
- Mis à jour le : 2020-11-19
- Catégorie : Tests
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tests/tests-unitaires-ou-integration-wordpress/

## L’essentiel

- Un test unitaire ne charge jamais le cœur WordPress
- Un test d'intégration charge une base de test complète
- Le choix dépend de ce que la fonction touche

Question posée en revue de code presque chaque semaine sur les projets qui adoptent les tests automatisés pour la première fois : « ce test doit-il hériter de `WP_UnitTestCase` ou d'un simple `PHPUnit\Framework\TestCase` ? ». La réponse ne dépend ni des habitudes ni de la mode, mais d'une seule question concrète : la fonction testée touche-t-elle à WordPress lui-même — base de données, hooks, options — ou se contente-t-elle de manipuler des données déjà en mémoire ?

Dans l'écosystème WordPress, le terme « test unitaire » est souvent utilisé à tort pour désigner ce qui est en réalité un test d'intégration, parce que `WP_UnitTestCase` porte ce nom malgré lui. La distinction mérite d'être clarifiée avec des exemples de code, pas seulement de la théorie.

## Un vrai test unitaire ne connaît pas WordPress

Un test unitaire, au sens strict, isole une fonction pure ou une classe, sans dépendance à une base de données, à un système de fichiers ou au cœur de WordPress. Il hérite de `PHPUnit\Framework\TestCase`, sans bootstrap WordPress :

```
use PHPUnit\Framework\TestCase;

final class Test_Formateur_Prix extends TestCase {

    public function test_applique_la_remise_fidelite() {
        $formateur = new Formateur_Prix();

        $prix = $formateur->calculer( 100.0, remise: 0.10 );

        $this->assertEquals( 90.0, $prix );
    }
}
```

Ce test s'exécute en quelques millisecondes, sans base de données ni installation WordPress. Il convient parfaitement à une classe de calcul de prix, un formateur de date, un validateur de format, ou toute logique métier isolable de WordPress.

## Un test d'intégration charge le cœur pour de vrai

Dès qu'une fonction appelle `get_post()`, `wp_insert_user()`, un hook, ou une option, il faut un test d'intégration, qui hérite de `WP_UnitTestCase` et s'exécute contre une base de données de test réelle :

```
class Test_Inscription_Formation extends WP_UnitTestCase {

    public function test_inscrit_un_utilisateur_a_une_formation() {
        $formation_id = self::factory()->post->create( array( 'post_type' => 'formation' ) );
        $user_id      = self::factory()->user->create();

        mon_plugin_inscrire( $user_id, $formation_id );

        $inscrits = get_post_meta( $formation_id, '_inscrits', true );
        $this->assertContains( $user_id, $inscrits );
    }
}
```

> L'essentiel à retenir : Un test unitaire ne charge jamais le cœur WordPress ; Un test d'intégration charge une base de test complète ; Le choix dépend de ce que la fonction touche

## Coût et vitesse : ce que ça change vraiment

La différence n'est pas que théorique : sur un projet avec plusieurs centaines de tests, la vitesse d'exécution devient un vrai sujet d'ergonomie de développement.

| Critère | Test unitaire | Test d'intégration |
| --- | --- | --- |
| Base de classe | PHPUnit\Framework\TestCase | WP_UnitTestCase |
| Base de données | Aucune | Base de test réelle, réinitialisée par transaction |
| Vitesse typique | Quelques millisecondes | 50 à 200 ms par test |
| Ce qu'il prouve | La logique pure est correcte | L'intégration avec WordPress fonctionne |

## Un exemple de code testable des deux façons

Le bon réflexe consiste à extraire la logique pure d'une fonction couplée à WordPress, pour pouvoir la tester en test unitaire pur, et ne garder le test d'intégration que pour la façade WordPress :

- Une fonction `calculer_remise( float $prix, int $anciennete_mois ): float` se teste en isolation totale
- La fonction `mon_plugin_appliquer_remise( int $user_id, int $produit_id )`, qui lit des métadonnées utilisateur puis appelle la première, nécessite un test d'intégration
- Séparer les deux permet d'écrire dix cas de calcul en tests unitaires rapides, et seulement deux ou trois tests d'intégration pour vérifier le branchement

## Notion à retenir : ce n'est pas un choix binaire

Un projet WordPress mature combine les deux niveaux plutôt que de choisir un camp. Les tests unitaires purs protègent la logique métier et s'exécutent en continu pendant le développement local ; les tests d'intégration valident que cette logique s'articule correctement avec les hooks, la base et l'API de WordPress, généralement lancés avant un commit ou en intégration continue.

## En résumé

La question à se poser n'est jamais « quel type de test dois-je écrire par principe », mais « qu'est-ce que cette fonction touche réellement ». Ce choix se fait fonction par fonction, pas projet par projet, et une bonne architecture de plugin facilite justement la multiplication des tests unitaires purs, moins coûteux à faire tourner. La stratégie de couverture globale à l'échelle d'une agence, elle, relève d'un arbitrage différent et plus organisationnel.
