Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to override step definitions in a behat context?

Tags:

behat

Is it possible to have have a subcontext class extend another subcontext and override functions?

At present I have

class TestContext extends BehatContext {
    /**
     * @Given /^a testScenarioExists$/
     */
    public function aTestscenarioexists() {
        echo "I am a generic test scenario\n";
    }
}

and

class SpecialTestContext extends TestContext {
    /**
     * @Given /^a testScenarioExists$/
     */
    public function aTestscenarioexists() {
       echo "I am a special test scenario\n";
    }
}

In feature context I tell it us the SpecialTestContext as a subcontext.

When I run the test behat complains with

[Behat\Behat\Exception\RedundantException]
Step "/^a testScenarioExists$/" is already defined in SpecialTestContext::aTestscenarioexists()

Can somebody please point in me the right direction with this ?

To give some further info as to why I'm trying to achieve this what I am trying to achieve is the ability to run scenarios with different environments, and have the environment specified in the gherkin file, for example:

Scenario: Test with generic environment
Given I am in the environment "generic"
    And a test scenario exists

Scenario: Test with specialised environment
Given I am in the environment "specialised"
    And a test scenario exists

I then can use add some code in FeatureContext to load up the correct sub-context.

like image 611
user2181503 Avatar asked Mar 18 '13 08:03

user2181503


Video Answer


2 Answers

As Rob Squires mentioned, the dynamic context loading will not work.

But I do have a workaround for overriding step definitions, that I use regularly. Don't annotate your method. Behat will pick up the annotation of the overridden method in the superclass, and will map that method name to the matching step. When a matching step is found, the method in your subclass will be invoked. To make it obvious, I've taken to using the @override annotation for this. The @override annotation has no special meaning to Behat.

class SpecialTestContext extends TestContext {
    /**
     * @override Given /^a testScenarioExists$/
     */
    public function aTestscenarioexists() {
       echo "I am a special test scenario\n";
    }
}
like image 82
zroger Avatar answered Oct 26 '22 14:10

zroger


In short...this is not possible : http://docs.behat.org/guides/2.definitions.html#redundant-step-definitions

In terms of loading subcontexts dynamically, this is not possible :

  1. Subcontexts are loaded at 'compile time' - ie. in the main FeatureContext constructor
  2. By the time the first step definition is run, behat has already collected all annotations and mapped them to step definitions, no more can/should be added

Check this out to understand how a Context behaves : http://docs.behat.org/guides/4.context.html#contexts-lifetime

Couple of wider things to consider :

  1. Anything captured in a gherkin scenario must be understandable by non-developers, (or at the very least developers who didn't write the system!). A scenario should convey in-full, one (ideally no more) business rule without having to dig into any code

  2. You don't want to hide too much logic up in step definitions, any rules should be captured in a gherkin scenario

  3. It's up to your how you organise your FeatureContexts, however your going to want to do this by themes/domains within your system, for example:

    • a DatabaseContext may be concerned with reading + writing to a test db
    • an ApiContext may contain steps concerned with validating an api within your system
    • an CommandContext may be concerned with validating your systems console commands
like image 34
Rob Squires Avatar answered Oct 26 '22 12:10

Rob Squires