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 parsh. 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.
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.
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 parProcess::fake(). Process::result() permet de définir la sortie standard, la sortie d’erreur et le code de sortie.
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 defake() 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, utilisezpreventStrayProcesses(). 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çoitIlluminate\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
- Documentation officielle de Laravel : processus
- Documentation officielle de Laravel : Process::fake et assertRan
- Process Factory : fake et assertRan
- PendingProcess : timeouts par défaut et correspondance des fakes
- ProcessResult : comportement de throw()
- ProcessFailedException : structure du message
- Facade : cache et swap()