Behat & Symfony's Process component
Here’s a super-quick way of using the Symfony Process Component in Behat Contexts to run processes in the background.
Chatting with a friend (@pieceofthepie) in the PHP East Midlands slack team and they said this:
The CI I’m playing with has a test step the needs me to start the php server, so I’m doing it in bash with a &
It works, but doing it ‘properly’ would maybe be better.
Now, we could argue the meaning of ‘properly’ all day (their method works, so what’s the problem?) but I thought I’d come up with an alternative for them.
Running background processes in Behat scenarios is something I’d done a number of times before in projects (scenarios required job workers to be running in the background to end-to-end test some async feature within an application) so this wouldn’t be too difficult to do with the Symfony Process Component.
I quickly came up with the following for them:
<?php
namespace App\Context;
use Behat\Behat\Context\Context;
use Symfony\Component\Process\Process;
class PhpServerContext implements Context
{
const TIMEOUT = 10;
/**
* @var Process
*/
protected $process;
/**
* @BeforeScenario @run-server
*/
public function startServerProcess()
{
$this->process = new Process('exec php -S localhost:8000 -t /path/to/my/public/directory');
$this->process->start();
}
/**
* @AfterScenario @run-server
*/
public function stopServerProcess()
{
$this->process->stop(self::TIMEOUT, SIGTERM);
$this->process = null;
}
}
Now tagging a scenario / feature with: @run-server
will mean that the PHP built-in webserver will be started before the scenario runs and will be listening on port :8000
. It’ll then stop the server when the scenario is finished - job done!
You could take this a step further and have it configurable for ports & docroot, maybe check if something is listening on that port already. Maybe have it run for the full suite, depends on your needs / use case.