Leçon 7 / 20

Remplacer les dépendances en test

25 min PHP 8 — architecture, tests et sécurité Gratuit

Objectif : Tester un cas d’usage en contrôlant les réponses du dépôt de contacts.

Un service métier fiable doit pouvoir être testé sans ouvrir de connexion à la base. Si le dépôt répond différemment selon les données, vous devez pouvoir reproduire chaque réponse et vérifier la réaction de ContactService.

Vous avez déjà testé le rejet de données invalides avec PHPUnit. Cette leçon ajoute un mock de DepotInterface : vous lui faites renvoyer un résultat déterminé, puis vérifiez que ContactService transmet bien l’opération au dépôt et restitue le résultat attendu. Le test n’a ainsi besoin ni de PDO ni d’une base de données.

Remplacer le dépôt par un mock

Un mock est une doublure créée par PHPUnit à partir d’une interface ou d’une classe. Vous pouvez configurer son comportement, par exemple lui faire renvoyer l’identifiant d’un contact ajouté, puis lui demander de vérifier qu’une méthode a été appelée avec les arguments attendus. Le mock remplace ici ContactDepot, mais le service continue de dépendre du contrat DepotInterface.

Complétez tests/Unitaire/ContactServiceTest.php avec un test de réussite. L’exemple contrôle à la fois les paramètres envoyés au dépôt et la valeur retournée par le service. Il illustre une convention de retour courante pour l’ajout : le dépôt renvoie l’identifiant attribué au contact.

PHP
<?php

declare(strict_types=1);

namespace Tests\Unitaire;

use App\Depot\DepotInterface;
use App\Service\ContactService;
use PHPUnit\Framework\TestCase;

final class ContactServiceTest extends TestCase
{
    public function testAjoutTransmetLesDonneesEtRetourneLIdentifiant(): void
    {
        $depot = $this->createMock(DepotInterface::class);
        $depot->expects(self::once())
            ->method('ajouter')
            ->with('Ada Lovelace', '[email protected]', '0123456789')
            ->willReturn(42);

        $service = new ContactService($depot);

        $identifiant = $service->ajouter(
            'Ada Lovelace',
            '[email protected]',
            '0123456789'
        );

        self::assertSame(42, $identifiant);
    }
}
Résultat attendu
OK (1 test, 2 assertions)

Le mock est configuré avant l’appel au service. expects(self::once()) impose un appel, tandis que with(...) vérifie les trois valeurs transmises. Enfin, willReturn(42) simule la réponse du dépôt : le test s’assure que le service renvoie bien cette réponse, sans qu’un enregistrement réel soit effectué.

Vérifier qu’une entrée invalide s’arrête avant le dépôt

Le test de rejet déjà présent peut également contrôler les interactions. Configurez le mock pour n’accepter aucun appel, puis transmettez une adresse invalide au service. Si la validation métier lève bien InvalidArgumentException avant la persistance, l’assertion d’exception passe et PHPUnit confirme qu’aucune méthode du dépôt n’a été invoquée.

PHP
public function testCourrielInvalideNeContactePasLeDepot(): void
{
    $depot = $this->createMock(DepotInterface::class);
    $depot->expects(self::never())->method('ajouter');

    $service = new ContactService($depot);

    $this->expectException(\InvalidArgumentException::class);
    $service->ajouter('Ada Lovelace', 'adresse-invalide', '0123456789');
}
Résultat attendu
OK si le service rejette le courriel avant l’appel au dépôt.

Intégrez cette méthode à votre fichier de test existant, en conservant son espace de noms, ses imports et les tests avec jeu de données déjà écrits. Si votre dépôt expose une méthode distincte pour l’ajout, remplacez ajouter par son nom réel. Les signatures exactes de DepotInterface et de ContactService restent celles de votre projet ; les exemples supposent la convention explicitée plus haut.

Lancer et interpréter les tests

Depuis la racine du projet, lancez la suite unitaire avec la commande ci-dessous. Vérifiez le résultat du test de succès, puis modifiez temporairement une valeur attendue dans with(...) : le test doit échouer, ce qui confirme que l’interaction est effectivement contrôlée. Restaurez ensuite la valeur correcte et relancez la suite.

Terminal
vendor/bin/phpunit tests/Unitaire
Résultat attendu
PHPUnit exécute les tests unitaires du répertoire. Les résultats précis dépendent du nombre de tests et de la configuration de votre projet.

Si PHPUnit signale que la méthode configurée n’existe pas ou que le type de retour est incompatible, confrontez le test à DepotInterface et aux méthodes réelles de ContactService. Ce n’est pas une invitation à inventer une nouvelle API : adaptez le scénario aux signatures déjà établies, tout en conservant l’objectif du test, à savoir contrôler la réponse du dépôt et vérifier le comportement du service.

À retenir

  • Créez un mock à partir de DepotInterface pour tester ContactService sans base de données.
  • Utilisez willReturn() pour contrôler la réponse simulée du dépôt.
  • Utilisez expects() et with() pour vérifier les appels et leurs arguments.
  • Vérifiez qu’une entrée invalide est rejetée sans interaction avec le dépôt.

La prochaine leçon étendra les vérifications aux parcours fonctionnels du carnet.

Envie d'aller plus loin ?

Les cours Enovatic sont gratuits et le resteront. Si vous cherchez un accompagnement encadré, nos formations professionnelles sont animées par les mêmes formateurs.