Sur un projet pour un client qui exposait un catalogue de formations via une route REST personnalisée, l’équipe testait la route à la main avec Postman avant chaque mise en production. Le jour où un développeur a renommé un paramètre de requête sans prévenir personne, le formulaire de recherche du site a silencieusement cessé de renvoyer des résultats pendant trois jours. Un test d’intégration automatisé aurait suffi à l’attraper en quelques secondes.
WordPress fournit exactement l’outillage nécessaire pour ce genre de vérification, sans passer par un vrai serveur HTTP : la classe WP_REST_Request et la fonction rest_do_request(). Elles permettent de simuler une requête entrante, de la faire passer par le routeur REST du cœur, et d’inspecter la réponse comme si un client l’avait réellement envoyée.
Pourquoi simuler plutôt qu’appeler un vrai point de terminaison
Faire un appel HTTP réel dans une suite de tests pose plusieurs problèmes : il faut un serveur qui tourne, l’authentification par cookie ou par application password devient pénible à automatiser, et chaque test devient lent. En passant par rest_do_request(), la requête traverse tout le cycle de vie REST de WordPress (permission_callback, validate_callback, sanitize_callback, callback) en restant dans le même processus PHP que le test. C’est rapide, déterministe, et cela permet d’inspecter directement l’objet WP_REST_Response retourné plutôt que de parser du JSON brut.
Mettre en place le test d’intégration
La classe de base à utiliser est WP_Test_REST_TestCase (ou simplement WP_UnitTestCase si vous préférez rester générique). Il faut d’abord s’assurer que le serveur REST est initialisé avant d’envoyer une requête :
class Test_Formations_Route extends WP_Test_REST_TestCase {
public function setUp(): void {
parent::setUp();
global $wp_rest_server;
$wp_rest_server = new WP_REST_Server();
do_action( 'rest_api_init' );
}
public function test_liste_les_formations_publiees() {
$request = new WP_REST_Request( 'GET', '/mon-plugin/v1/formations' );
$request->set_param( 'categorie', 'developpement' );
$response = rest_do_request( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertIsArray( $data );
}
}

Vérifier le statut, les en-têtes et le schéma de réponse
Une route REST bien testée ne se contente pas de vérifier le code 200. Il faut aussi contrôler la forme des données retournées, surtout si un schema a été déclaré via register_rest_route(). Quelques assertions utiles :
assertArrayHasKey( 'id', $item )sur chaque élément du tableau retournéassertSame( 'application/json', $response->get_headers()['Content-Type'] )pour l’en-tête de contenu$response->get_matched_route()pour confirmer que la bonne route a été résolue en cas d’ambiguïté- Comparaison du tableau retourné avec le schéma déclaré, via
rest_validate_value_from_schema()côté test
Tester les permissions et les capacités
Le permission_callback est souvent le point le plus fragile d’une route, et pourtant le moins testé en pratique. Il suffit de changer d’utilisateur courant avant d’envoyer la requête pour couvrir chaque cas :
public function test_refuse_la_creation_sans_capacite() {
$abonne = self::factory()->user->create( array( 'role' => 'subscriber' ) );
wp_set_current_user( $abonne );
$request = new WP_REST_Request( 'POST', '/mon-plugin/v1/formations' );
$request->set_param( 'titre', 'Atelier PHPUnit' );
$response = rest_do_request( $request );
$this->assertEquals( 401, $response->get_status() );
}
Il est important de tester au minimum trois profils : un visiteur non connecté, un rôle qui ne devrait pas avoir accès, et un rôle qui devrait pouvoir agir. Ce triptyque suffit à couvrir la majorité des régressions de permission_callback rencontrées sur des extensions professionnelles.
Simuler des paramètres invalides
Enfin, un point souvent négligé : vérifier que les validate_callback et sanitize_callback déclarés dans args fonctionnent réellement. Un paramètre categorie censé n’accepter que des valeurs d’une liste fermée doit renvoyer une erreur 400 si on lui passe une valeur absurde :
$request->set_param( 'categorie', 'inexistante' );
$response = rest_do_request( $request );
$this->assertEquals( 400, $response->get_status() );
Sur nos projets, la règle est simple : toute route REST qui accepte une écriture (POST, PUT, DELETE) doit avoir au moins un test de permission_callback avant d’être fusionnée. C’est la ligne de défense la moins chère à écrire et la plus souvent oubliée.
En résumé
Tester une route REST personnalisée ne demande ni serveur, ni client HTTP, ni bibliothèque tierce : WP_REST_Request et rest_do_request() suffisent à couvrir le statut, le schéma et les permissions directement dans PHPUnit. Le mock des dépendances vers des API tierces appelées depuis le callback est un sujet à part entière, qui mérite son propre traitement plutôt que d’être mélangé à ces vérifications de base.