Running commands between features and scenarios in Behat v3
This article was originally published at http://adamquaile.com/running-commands-between-features-and-scenarios-in-behat on 12th Oct 2014, but has since been migrated to Medium.
When using Behat for any application with more than a small amount of complexity, I often find there’s tasks I do time and time again.
Maybe, at the start of the test suite I need to clear my cache; in a symfony environment this might look something like this:
php app/console cache:clear --env=test
Maybe I want to reset the database after each feature, or each scenario…
php app/console -e test doctrine:database:drop
php app/console -e test doctrine:database:create
php app/console -e test doctrine:schema:update
Some common ways
Of course, we have behat hooks like @BeforeSuite
, @BeforeScenario
, etc.. so we can write code like this in our context files
<?php /**
* @BeforeSuite
*/
public static function beforeSuite()
{
exec('php app/console cache:clear --env=test');
}
I’ve also seen more complex test scripts like this:
#!/bin/bash# Some test prep
php app/console -e test doctrine:database:drop
php app/console -e test doctrine:database:create
php app/console -e test doctrine:schema:update# Maybe run the PHP built-in server, PhantomJS or Selenium...
./run-server-or-daemon
pid=$!./bin/behat# ...and stop it when the tests have finished
kill $pid
These all work and, depending on your situation, might be exactly what you’re looking for. Like any solution to a problem they have their limitations.
I’ve been experimenting with on more way:
The behat command-runner extension
I’ve created a proof-of-concept extension to behat which allows us to specify these commands to be run right from inside behat.yml
.
Let me share an extract from one of my recent projects:
---
extensions: AdamQuaile\Behat\CommandRunnerExtension:
beforeSuite:
- rm -rf ./app/cache/test/*
- php app/console doctrine:database:drop --env=test --force
- php app/console doctrine:database:create --env=test --force
- php app/console doctrine:schema:update --env=test --force
- cp app/test.db3 app/test.initial.db3
beforeFeature:
- cp app/test.initial.db3 app/test.db3
What’s happening here is fairly self-explanatory. At the beginning of the suite we setup the test database (we’re not using any fixtures here, but we could very simply). Also for speed, instead of recreating the database using doctrine each feature, we’re backing up and restoring the initial state of a SQLite database.
It also supports running background tasks, like this:
---
beforeSuite:
- { command: 'ping example.com', background: true }
The code is hosted over on github and available through composer
.
You’ll have to require with @dev
as it's still an early proof-of-concept. I'd love feedback on whether this works for your projects, and how it could be better.
Learning PHP? The language is just the beginning.
Get to grips with testing tools like Behat, PHPSpec, PHPUnit, and more.