Passer au contenu principal
Lorsqu’un package appelle des commandes externes comme ffmpeg ou git, les différences d’environnement de l’application qui l’utilise et les échecs deviennent directement le comportement du package. Au lieu d’appeler directement shell_exec() ou exec(), exécutez les commandes via la facade Process et remplacez-les par Process::fake() dans les tests.
Cette page cible Laravel 13 et vérifie l’implémentation de Framework v13.42.0. Elle suppose connus les processus et les tests de packages. La correspondance des commandes en tableau traitée ici repose sur la conversion des arguments par Symfony Process, que Process utilise en interne.

Pourquoi éviter l’exécution directe

Les appels directs de fonctions ne peuvent pas être remplacés dans les tests, et chaque appelant gère différemment les timeouts et les codes de sortie. En passant par la facade Process, vous unifiez l’enregistrement des exécutions, les fakes, les timeouts et les exceptions en cas d’échec.

Passer les commandes sous forme de tableau

Une commande sous forme de chaîne est interprétée par sh. Si elle contient une saisie utilisateur, des problèmes de guillemets et des risques d’injection apparaissent. À l’intérieur d’un package, passez les arguments sous forme de tableau.
Le timeout par défaut de PendingProcess est de 60 secondes et le timeout d’inactivité vaut null. Pour les conversions longues, indiquez explicitement timeout(), et pour les traitements dont la sortie peut s’arrêter, ajoutez idleTimeout().

Exceptions et messages en cas d’échec

ProcessResult::throw() lève une ProcessFailedException lorsque le code de sortie n’indique pas un succès. Le message contient la commande exécutée, le code de sortie, ainsi que la sortie standard et la sortie d’erreur.
Si vous placez des secrets dans les arguments de la commande, ils se retrouvent dans le message de ProcessFailedException et peuvent apparaître dans les logs ou à l’écran. Ne passez pas les tokens en arguments. Transmettez-les avec env() ou écrivez-les dans le fichier de configuration de la commande.
Les timeouts sont représentés par ProcessTimedOutException et les timeouts d’inactivité par ProcessIdleTimedOutException. Documentez pour les utilisateurs du package quelles exceptions vous levez et ce qu’ils peuvent attendre en les interceptant.

Utiliser des fakes dans les tests

Dans les tests, remplacez les commandes externes par Process::fake(). Process::result() permet de définir la sortie standard, la sortie d’erreur et le code de sortie.
En passant une closure à assertRan(), vous pouvez vérifier command, timeout, environment et d’autres propriétés de PendingProcess. Les commandes en tableau sont comparées à $process->command par égalité exacte, de sorte que les tests détectent les changements d’ordre ou de valeur des arguments.

Clés de fake pour les commandes en tableau

En interne, Process compare les clés de fake() au résultat de getCommandline() avec Str::is(). Les commandes en tableau sont converties en chaîne entre guillemets pour le shell, donc un motif de chaîne comme 'ffmpeg*' ne correspond pas. Pour tester des commandes en tableau, utilisez l’une des approches suivantes.

Empêcher les commandes externes inattendues

Pour détecter les commandes externes qui ne devraient pas s’exécuter dans les tests, utilisez preventStrayProcesses(). Les commandes qui ne correspondent à aucun fake lèvent une RuntimeException et ne sont jamais réellement lancées.

Si vous utilisez une Factory injectée

Si le constructeur de votre package reçoit Illuminate\Process\Factory, vérifiez que l’état de Process::fake() atteint bien l’instance injectée. La facade met en cache l’instance résolue, et swap() remplace l’instance dans le conteneur. En revanche, vous ne pouvez pas compter sur un enregistrement explicite par le framework pour que Factory soit partagée dans le conteneur : vérifiez-le donc dans un test. Si le fake n’atteint pas l’instance injectée, remplacez explicitement la Factory dans le test ou concevez le package pour qu’il passe par la facade Process. Dans les deux cas, vérifier avec assertRan() que l’appel a été enregistré permet de détecter un remplacement oublié.

Vérifications à ajouter pour la maintenance à long terme

Sources primaires consultées

Dernière modification le 13 novembre 2026