Question

Behat by default looks for the step definitions in file named FeatureContext (all steps in one file).
Having a lot of steps, it's hard to maintain such a big file.

I'd like to have one definition file per feature file.

How can I have step definitions in external files?

e.g.

homepage.feature
HomepageContext extends FeatureContext
Was it helpful?

Solution

Use class inheritance and separate contexts.

# /features/contexts/
AbstractContext extends BehatContext {}
FeaturenameContext extends AbstractContext {}

Then in /feature/FeatureContext.php import the context files:

/**
 * Initializes context.
 * Every scenario gets it's own context object.
 *
 * @param array $parameters context parameters (set up via behat.yml)
 */
public function __construct(array $parameters) {

    // import all context classes from context directory, except the abstract one

    $filesToSkip = array('AbstractContext.php');

    $path = dirname(__FILE__) . '/../contexts/';
    $it = new RecursiveDirectoryIterator($path);
    /** @var $file  SplFileInfo */
    foreach ($it as $file) {
        if (!$file->isDir()) {
           $name = $file->getFilename();
           if (!in_array($name, $filesToSkip)) {
               $class = pathinfo($name, PATHINFO_FILENAME);
               require_once dirname(__FILE__) . '/../context/' . $name;
               $this->useContext($class, new $class($parameters));
           }
        }
    }
}

OTHER TIPS

Behat has multiple options for you to split up your FeatureContext into multiple classes. First, you can use old-school php5 inheritance. If the inheritance is not what you want, Behat also supports subcontexts: "Using Subcontexts".

Next, if you want to name your class differently than FeatureContext, you can redefine that in "Context Configuration" section of your behat.yml config file.

This way, you could split common definitions and hooks into separate classes and use them in other feature suites as well with either subcontexting or inheritance.

But your question also asks:

I'd like to have one definition file per feature file.

This request is totally wrong. Behat and Scenario BDD is all about describing your application behavior in business terms and creating test dictionary for described behaviors. Keeping that in mind, you logically couldn't have multiple different dictionaries for one feature-set. By writing step definitions, you're telling Behat what that Given I am on "/news" means. And when you want that step to mean different things from feature to feature - you're doing it wrong.

Behat consists of 2 main and enough separate concepts:

  1. *.feature files, written in Gherkin language. Those files should be self-descriptive. Means, that they should provide all the information for the reader in order to understand them. Gherkin is not a new programming language for your functional tests, it's just a markdown for your user-stories!
  2. FeatureContext.php classes, describes how Behat should test your features. It defines application-wide dictionary to be used with whole application feature-suite. This is a programming bridge between your markdown-like user-stories and actual functional tests.

And you shouldn't mess this things up. Single feature suite should have single steps dictionary (definitions). But you could use single dictionary in more than one feature suite thanks to inheritance and subcontexts. And yes, you can split single suite dictionary into multiple php classes ;-)

One solution is horizontal reusability with subContexts. Use a subContext for each "feature group".

class FeatureContext extends BehatContext
{

    public function __construct(array $context_parameters)
    {
        $this->useContext('math_context', new MathContext());
        $this->useContext('bash_context', new BashContext());
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top