ffmpeg or git, differences in the host application’s environment and command failures become the package’s behavior. Instead of calling shell_exec() or exec() directly, run commands through the Process facade and replace them with Process::fake() in tests.
This page targets Laravel 13 and checks the implementation of Framework
v13.42.0. It assumes processes and package testing. The array command matching covered here relies on how Symfony Process, which Process uses internally, converts arguments.Why to avoid direct execution
Direct function calls cannot be swapped out in tests, and each caller handles timeouts and exit codes differently. Going through the Process facade gives you one consistent way to record runs, fake them, apply timeouts and throw exceptions on failure.Pass commands as arrays
A string command is interpreted bysh, so including user input opens the door to quoting problems and injection. Inside a package, pass arguments as an array.
PendingProcess is 60 seconds, and the idle timeout is null. Set timeout() explicitly for long conversions, and add idleTimeout() for work whose output can stall.
Exceptions and messages on failure
ProcessResult::throw() throws ProcessFailedException when the exit code is not successful. The message contains the command that ran, the exit code, and the standard output and standard error output.
Timeouts are represented by ProcessTimedOutException, and idle timeouts by ProcessIdleTimedOutException. Document for your package’s users which exceptions you throw and what they can expect when they catch them.
Fake in tests
In tests, replace external commands withProcess::fake(). Process::result() lets you specify the standard output, the standard error output and the exit code.
assertRan(), you can check the command, timeout, environment and other properties of PendingProcess. Array commands are compared with $process->command by exact match, so tests detect changes to the order or values of arguments.
Fake keys for array commands
Internally, Process matches the keys passed tofake() against the result of getCommandline() with Str::is(). Array commands are converted into a quoted string for the shell, so a string pattern such as 'ffmpeg*' does not match. For tests of array commands, use one of the following.
Prevent unexpected external commands
To detect external commands that should not run in tests, usepreventStrayProcesses(). Commands that do not match a fake throw a RuntimeException and never actually start.
When you use an injected Factory
If your package’s constructor receivesIlluminate\Process\Factory, check whether the Process::fake() state reaches the injected instance. The facade caches the resolved instance, and swap() replaces the instance in the container. Whether Factory is shared in the container, however, is not something you can rely on the framework to register explicitly, so verify it in a test.
If the fake does not reach the injected instance, swap the Factory explicitly in the test or design the package to go through the Process facade. In either case, confirming with assertRan() that the call was recorded lets you catch a missed swap.