Running commands between features and scenarios in Behat v3

Adam Quaile
Aug 1, 2017 · 2 min read

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.

Adam Quaile

Written by

PHP developer. http://t.co/olQvZ91Lo4

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade