I recently started working on a project that will rely heavily on running commands on the terminal. It quickly got in my way of doing TDD, so I had to implement some sort of ProcessFake. This article is about how easy that was.
The mental process that I used to write a Process::fake()
was based on the same logic of Mail::fake()
, Storage::fake()
and Queue::fake()
. It’s basically a bridge between your system and some external service.
The Process Facade is extremely simple: it executes a process. It’s a simple wrapper around Symfony Process.
Suppose we want to write a WebServerController
that exposes the ability to restart the Web Server. Following the TDD approach, I would like to write a test like the following:
For the test to pass, we’ll need to write the ProcessFake
class as well as the actual implementation of the Controller
.
Special attention to use Facades\App\Process
. This is a Real-time Facade. It means that Laravel will generate a Facade on-the-fly for the class. You can read more about it here.
To finish the details required on (2), an implement for ProcessFake
capable of asserting that a command was executed.
Don’t forget to register the Route before running your tests:
Route::post('/webserver/restart', 'WebServerController@restart');
To recap, an extremely simple wrapper around Symfony Process as a Facade will allow us to execute commands that the application offers. Because we’re using a Real-time Facade, we can swap the implementation with a Fake
for our Feature tests.
One may raise the question: What guarantee that the Process
Facade actually works? A test coverage report can tell that there are no coverage for the actual Process
implementation. A solution for that is to write one simple Integration test.
For an integration test, we can write a simple bash
script that can be executed in any Continuous Integration platform (such as TravisCI). For that, we provide the bash file with the test and write a test that runs it.
And the simple bash script
#!/bin/bashecho 'process output'
For Travis, add execution permission to the script:
script: chmod a+x ./tests/Integration/process.sh && vendor/bin/phpunit --verbose
Done!
Feel free to follow me on Medium for more articles like this one.