Un test qui dépend de données déjà présentes dans la base n’est pas un test, c’est un pari. Si le contenu change, si un autre développeur supprime un article, si l’ordre d’exécution des tests varie, le résultat devient imprévisible. WP_UnitTestCase résout ce problème avec un mécanisme de factories qui crée des objets WordPress à la demande, et les annule proprement une fois le test terminé.
Comprendre ces factories change radicalement la façon d’écrire des tests sur WordPress : au lieu de préparer manuellement un jeu de données fragile, vous décrivez dans chaque test exactement ce dont il a besoin, ni plus ni moins. Voici comment les utiliser efficacement, avec les pièges à éviter.
Le principe : une transaction annulée à chaque test
Avant chaque méthode de test, WP_UnitTestCase ouvre une transaction MySQL. Tout ce que vous créez pendant le test, posts, utilisateurs, options, termes de taxonomie, est inséré normalement en base. Mais à la fin du test, la classe exécute un ROLLBACK qui annule tout. Résultat concret : votre base de test reste vide entre deux tests, sans qu’il soit nécessaire d’écrire le moindre code de nettoyage.
C’est ce mécanisme qui autorise à créer librement des contenus dans vos tests sans craindre de polluer les suivants. C’est aussi la raison pour laquelle les tests basés sur WP_UnitTestCase ne conviennent pas à des scénarios qui dépendent explicitement de transactions MySQL applicatives : le rollback global de la classe de test entrerait en conflit.
Créer des données avec factory()
La méthode $this->factory() expose un ensemble d’objets qui savent créer chaque type de contenu WordPress. Les plus utilisés :
$this->factory()->post->create( $args ): crée un article et retourne son ID.$this->factory()->post->create_and_get( $args ): crée un article et retourne directement l’objetWP_Post.$this->factory()->user->create( $args ): crée un utilisateur.$this->factory()->term->create( $args ): crée un terme de taxonomie.$this->factory()->comment->create( $args ): crée un commentaire.$this->factory()->attachment->create_upload_object( $chemin_fichier ): crée une pièce jointe à partir d’un fichier réel.

Exemple : tester une fonction qui filtre des articles par auteur
Imaginons une fonction mon_plugin_get_articles_publies_par( $user_id ) qui retourne uniquement les articles publiés d’un auteur donné. Un test complet ressemble à ceci :
class Test_Articles_Par_Auteur extends WP_UnitTestCase {
public function test_ne_retourne_que_les_articles_publies() {
$auteur = $this->factory()->user->create( array(
'role' => 'author',
) );
$publie = $this->factory()->post->create( array(
'post_author' => $auteur,
'post_status' => 'publish',
) );
$brouillon = $this->factory()->post->create( array(
'post_author' => $auteur,
'post_status' => 'draft',
) );
$resultats = mon_plugin_get_articles_publies_par( $auteur );
$this->assertContains( $publie, $resultats );
$this->assertNotContains( $brouillon, $resultats );
}
}
Ce test ne dépend d’aucune donnée préexistante : il crée exactement ce dont il a besoin, exécute la fonction testée, puis vérifie le résultat. À la fin du test, l’auteur et les deux articles disparaissent grâce au rollback.
Créer plusieurs objets d’un coup
Pour des scénarios nécessitant plusieurs contenus similaires, create_many() évite de répéter les appels :
$ids = $this->factory()->post->create_many( 5, array(
'post_status' => 'publish',
) );
$this->assertCount( 5, $ids );
Simuler une requête front avec go_to()
Certaines fonctions dépendent du contexte de la requête WordPress en cours, par exemple is_single(), get_queried_object() ou une fonction personnalisée qui inspecte $wp_query. La méthode $this->go_to( $url ) simule une navigation vers une URL donnée et reconstruit l’objet WP_Query en conséquence :
public function test_is_single_sur_un_article_publie() {
$post_id = $this->factory()->post->create();
$this->go_to( get_permalink( $post_id ) );
$this->assertTrue( is_single() );
$this->assertEquals( $post_id, get_queried_object_id() );
}
Sans go_to(), is_single() retournerait systématiquement false dans un test, puisque aucune requête réelle n’a été effectuée.
Assertions spécifiques à WordPress
WP_UnitTestCase ajoute des assertions au-delà de celles de PHPUnit, notamment :
assertWPError( $actual ): vérifie qu’une valeur est bien un objetWP_Error.assertQueryTrue( ...$conditions ): vérifie qu’un ensemble précis de fonctions conditionnelles de la boucle (is_home,is_archive, etc.) retournenttrue, et que toutes les autres retournentfalse.assertEqualSets( $expected, $actual ): compare deux tableaux sans tenir compte de l’ordre des éléments, pratique pour comparer des listes d’IDs.
Sur nos projets, nous évitons de créer des données dans une méthode
setUp()partagée par toute une classe de test dès que ces données ne servent pas à tous les tests de la classe. UnsetUp()trop chargé rend chaque test plus lent, et surtout plus difficile à comprendre isolément.
En résumé
Les factories de WP_UnitTestCase transforment l’écriture de tests WordPress en un exercice rapide et lisible : chaque test décrit ses propres données, sans effet de bord sur les suivants. Combinées à go_to() pour le contexte de requête et aux assertions spécifiques comme assertWPError(), elles couvrent la grande majorité des besoins de test d’un plugin ou d’un thème. La prochaine étape, pour les tests qui n’ont pas besoin du cœur WordPress, consiste à explorer des outils plus légers comme Brain Monkey.