Running commands between features and scenarios in Behat v3

Adam Quaile
2 min readAug 1, 2017

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.

Professional PHP Book Cover

Learning PHP? The language is just the beginning.

Get to grips with testing tools like Behat, PHPSpec, PHPUnit, and more.

https://leanpub.com/professional-php

--

--