vendredi 25 septembre 2026

À propos

Contact

Tests

Mocker les appels API externes dans vos tests PHPUnit WordPress

Un test qui dépend d'une API tierce réelle est lent, fragile et parfois payant à chaque exécution. Voici comment intercepter proprement wp_remote_get et consorts avec le filtre pre_http_request.

Par Clément Hadrot • 5 décembre 2023 • 5 min de lecture • Aucun commentaire
Mocker les appels API externes dans vos tests PHPUnit WordPress

Beaucoup de plugins WordPress communiquent avec des services externes : une API de paiement, un service de géolocalisation, une plateforme d’emailing. Tester le code qui orchestre ces appels pose un problème classique : si le test effectue un véritable appel réseau, il devient lent, dépend de la disponibilité du service tiers au moment précis de l’exécution, et peut même engendrer des coûts réels si l’API est facturée à l’appel. La solution ne consiste pas à éviter de tester ce code, mais à intercepter l’appel HTTP avant qu’il ne quitte réellement le serveur.

WordPress fournit pour cela un point d’extension natif, le filtre pre_http_request, qui permet de court-circuiter n’importe quel appel passant par WP_Http, la classe qui sous-tend toutes les fonctions wp_remote_*(). Voici comment l’exploiter proprement dans une suite PHPUnit.

Comprendre le filtre pre_http_request

Toute requête HTTP sortante initiée par WordPress, que ce soit via wp_remote_get(), wp_remote_post() ou directement via la classe WP_Http, passe par ce filtre avant l’exécution réelle de la requête réseau. Si une fonction accrochée à ce filtre retourne autre chose que false (sa valeur par défaut), WordPress considère que la réponse a déjà été fournie et n’effectue jamais l’appel réseau réel.

add_filter( 'pre_http_request', function( $preempt, $args, $url ) {
    // Retourner un tableau de réponse simulé court-circuite l'appel réel
    return false; // false = laisser passer l'appel réel
}, 10, 3 );

C’est exactement ce mécanisme que l’on exploite dans un test pour simuler la réponse d’une API externe sans jamais sortir du serveur de test.

Simuler une réponse d’API réussie

Supposons une fonction mon_plugin_get_taux_change( $devise ) qui interroge une API de taux de change :

function mon_plugin_get_taux_change( $devise ) {
    $reponse = wp_remote_get( "https://api.exemple.com/taux/{$devise}" );

    if ( is_wp_error( $reponse ) ) {
        return null;
    }

    $corps = wp_remote_retrieve_body( $reponse );
    $donnees = json_decode( $corps, true );

    return $donnees['taux'] ?? null;
}

Le test simule la réponse HTTP attendue, dans le format exact que retourne WP_Http, avec les clés body, response et headers :

class Test_Taux_Change extends WP_UnitTestCase {

    public function test_recupere_le_taux_depuis_lapi() {
        add_filter( 'pre_http_request', function( $preempt, $args, $url ) {
            return array(
                'body'     => wp_json_encode( array( 'taux' => 1.08 ) ),
                'response' => array( 'code' => 200, 'message' => 'OK' ),
                'headers'  => array(),
            );
        }, 10, 3 );

        $taux = mon_plugin_get_taux_change( 'USD' );

        $this->assertEquals( 1.08, $taux );
    }
}
L'essentiel à retenir : Un filtre natif WordPress pour intercepter toute requête HTTP sortante ; Des tests qui ne dépendent plus de la disponibilité d'un service tiers ; Une réponse simulée fidèle au format réel de l'API

Simuler une erreur réseau

Il est tout aussi important de tester le comportement du code face à un échec : timeout, service indisponible, réponse malformée. Le filtre pre_http_request peut également retourner un objet WP_Error, exactement comme le ferait WP_Http en cas d’échec réel :

public function test_retourne_null_en_cas_derreur_reseau() {
    add_filter( 'pre_http_request', function() {
        return new WP_Error( 'http_request_failed', 'Délai dépassé' );
    } );

    $taux = mon_plugin_get_taux_change( 'USD' );

    $this->assertNull( $taux );
}

Ce type de test révèle souvent des bugs latents : une fonction qui suppose implicitement que wp_remote_get() réussit toujours, sans vérifier is_wp_error(), plante en production au premier incident réseau du service tiers, un incident que ce test rend justement facile à reproduire à volonté.

Nettoyer le filtre entre chaque test

Un piège fréquent : oublier de retirer le filtre ajouté dans un test, ce qui contamine les tests suivants dans la même classe. La méthode tearDown() doit systématiquement nettoyer ce qui a été ajouté :

protected function tearDown(): void {
    remove_all_filters( 'pre_http_request' );
    parent::tearDown();
}

Sur les projets où plusieurs tests simulent des appels HTTP différents dans la même classe, ce nettoyage systématique dans tearDown() évite des heures de débogage face à un test qui échoue de façon incompréhensible parce qu’un filtre laissé par le test précédent intercepte encore la requête.

Vérifier que l’appel a bien été effectué avec les bons paramètres

Au-delà de simuler la réponse, on peut aussi vérifier que la requête sortante contient les bons paramètres, en inspectant les arguments $args et $url fournis au filtre :

public function test_envoie_la_bonne_devise_dans_lurl() {
    $url_capturee = null;

    add_filter( 'pre_http_request', function( $preempt, $args, $url ) use ( &$url_capturee ) {
        $url_capturee = $url;
        return array( 'body' => wp_json_encode( array( 'taux' => 1.0 ) ), 'response' => array( 'code' => 200 ) );
    }, 10, 3 );

    mon_plugin_get_taux_change( 'GBP' );

    $this->assertStringContainsString( 'GBP', $url_capturee );
}

Sur nos projets, nous interdisons purement et simplement les appels réseau réels dans une suite PHPUnit exécutée en CI. Un test qui dépend de la disponibilité d’un service tiers à un instant précis n’est plus un test fiable : c’est un pari sur la météo du réseau ce jour-là.

En résumé

Le filtre pre_http_request offre un point d’interception natif et fiable pour tester tout code WordPress qui communique avec un service externe, sans jamais quitter le serveur de test. Simuler à la fois les réponses réussies et les erreurs réseau, tout en nettoyant systématiquement les filtres ajoutés dans tearDown(), permet de couvrir des cas d’échec qu’il serait risqué, voire impossible, de déclencher volontairement sur une vraie API tierce.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi