Refactoring executable Gherkin with Gwen to eliminate redundancy

In the previous post we walked through an example of converting an executable Gherkin specification from feature to scenario level state.

The example we converted was this one:

gwen-workspace/samples/todo/feature-level/Todo.feature

 Feature: Create and complete Todo items

Scenario: Add items in my Todo list
    Given I launch the Todo app
     When I add a "Walk the dog" item
      And I add a "Get the milk" item
      And I add a "Feed the cat" item
     Then the number of open items should be "3"

Scenario: Complete second item
    Given I am on the Todo page
     When I complete the "Get the milk" item
     Then the number of open items should be "2"

Scenario: Complete first item
    Given I am on the Todo page
     When I complete the "Walk the dog" item
     Then the number of open items should be "1"

Scenario: Complete third item
    Given I am on the Todo page
     When I complete the "Feed the cat" item
     Then the number of open items should be "0"

Scenario: Clear my completed items
    Given I am on the Todo page
     When I clear all completed items
     Then the number of open items should not be displayed

In this example, all scenarios execute one after the other in the exact order shown and accumulate feature-level state. Each scenario depends on the one before it and executing them in a different order would result in execution failure. Writing executable Gherkin in this manner in not considered good practice since the scenarios are not self contained and leak state from one scenario to the next. Each scenario does however perform a test (or check) and the specification as a whole executes in one browser session to load three items, complete them individually and then clear the completed list.

The result of the conversion from feature to scenario level state was the following specification:

gwen-workspace/samples/todo/scenario-level/Todo.feature

   Feature: Create and complete Todo items

Background: Add items to my Todo list
      Given I launch the Todo app
       When I add a "Walk the dog" item
        And I add a "Get the milk" item
        And I add a "Feed the cat" item
       Then the number of open items should be "3"

  Scenario: Complete second item
      Given I am on the Todo page
       When I complete the "Get the milk" item
       Then the number of open items should be "2"

  Scenario: Complete second and first item
      Given I am on the Todo page
       When I complete the "Get the milk" item
        And I complete the "Walk the dog" item
       Then the number of open items should be "1"

  Scenario: Complete second, first, and third item
      Given I am on the Todo page
       When I complete the "Get the milk" item
        And I complete the "Walk the dog" item
        And I complete the "Feed the cat" item
       Then the number of open items should be "0"

  Scenario: Complete and clear all items
      Given I am on the Todo page
       When I complete the "Get the milk" item
        And I complete the "Walk the dog" item
        And I complete the "Feed the cat" item
        And I clear all completed items
       Then the number of open items should not be displayed

In this converted example, each scenario gets its own new and clean state. The scenarios are independent of each other and a common background sets up the same precondition for each one. The scenarios can execute in any order and do not leak any state. Each scenario performs a test (or check) in a new browser session.

However, there is a lot of redundancy here. For each scenario, the background starts a new browser session and adds three items to the list. Since there are four scenarios, this happens four times. The first scenario completes one of these items. The second scenario completes the same item that the first one did before completing another one. The third scenario completes the same two items as the last two did before completing the last remaining item. The fourth scenario then does everything all over again before clearing all items from the list. The specification takes longer to execute than the original which used feature-level state. Even if we execute these scenarios in parallel, we will still have lesser performance.

But fear not, we will now refactor this example into the single scenario below that will perform everything just once and eliminate all redundancy!

gwen-workspace/samples/todo/wip/Todo.feature

   Feature: Todo

  Scenario: Create and complete Todo items
      Given I have three open items
       When I complete each open item
        And I clear all completed items
       Then I should have no items left

If you haven’t installed Gwen, now is a good time to do it (just download and unpack the gwen-workspace.zip to a location on your drive).

Create a new samples/todo/wip folder in your Gwen workspace and save the new single scenario feature above in a file called Todo.feature in that directory.

Recall the following Gwen meta from the previous post that was used to make both our feature and scenario level specifications executable. Copy this meta specification to a file called Todo.meta in the newly created wip folder (the feature and meta files should both be there).

gwen-workspace/samples/todo/wip/Todo.meta

 Feature: Todo meta
  
@StepDef
Scenario: I launch the Todo app
    Given I start a new browser
     When I resize the window to width 800 and height 800
      And I navigate to "http://todomvc.com/examples/angularjs"
     Then I should be on the Todo page

@StepDef
Scenario: I should be on the Todo page
    Given the heading can be located by tag name "h1"
     Then the heading should be "todos"
      And I am on the Todo page
      And the todo field can be located by class name "new-todo"
      And the number of open items can be located by css selector ".todo-count > strong"
      And the clear completed button can be located by class name "clear-completed"
      And the number of open items should not be displayed

@StepDef
Scenario: I add a "<todo>" item
    Given the "$<todo>" item can be located by xpath "//label[contains(.,'$<todo>')]/preceding-sibling::input"
     When I enter "$<todo>" in the todo field
     Then the "$<todo>" item should be unchecked

@StepDef
Scenario: I complete the "<todo>" item
     When I tick the "$<todo>" item
     Then the "$<todo>" item should be ticked

@StepDef
Scenario: I clear all completed items
     When I click the clear completed button

We will be adding a few more step definitions to this meta to make our new feature executable.

Lets start with the first step in our Scenario:

Given I have three open items

Our step definition for this step should perform the exact same steps that the background in our previous feature performed. Create that step definition now by adding the following to the end of the gwen-workspace/samples/todo/wip/Todo.meta file:

@StepDef
Scenario: I have three open items
    Given I launch the Todo app
     When I add a "Walk the dog" item
      And I add a "Get the milk" item
      And I add a "Feed the cat" item
     Then the number of open items should be "3"

The @StepDef annotation tells Gwen that this is a step definition. Note that the scenario name matches the expression of the first Given step in our new feature. This is how step definitions work in Gwen.

We will now verify that this step definition works by testing it in the Gwen REPL. Open a command prompt in the root of your gwen-workspace directory and run the following command to load the meta and launch the REPL.

Linux/Mac/PowerShell:

./gwen -m samples/todo/wip/Todo.meta

Windows DOS:

gwen -m samples/todo/wip/Todo.meta
The meta will load and the gwen> will open. Enter our first feature step in the prompt and press enter to evaluate it.
gwen> Given I have three open items

Gwen will perform all the steps defined in our step definition for this step. The browser session will remain open once the step completes and you will see the three items added.

We have verified that our step definition works. Type exit at the gwen prompt to exit the REPL.

We will now move on to the next step in our scenario:

When I complete each open item

We will implement our step definition for this step by completing each of the items one at a time and verify the number of completed items displayed in the bottom left as we go. Add the following step definition to your meta:

@StepDef
Scenario: I complete each open item
    Given I am on the Todo page
     When I complete the "Get the milk" item
     Then the number of open items should be "2"
     When I complete the "Walk the dog" item
     Then the number of open items should be "1"
     When I complete the "Feed the cat" item
     Then the number of open items should be "0"
Launch the REPL again to load the meta as before. Press the up arrow a couple of times to recall the first step we evaluated earlier and press enter on it. Gwen will run the same previous steps as before and load all our items in to the list. Once that is done, type the second scenario step into the prompt and press enter to execute it. Gwen will complete all items as per the step definition we just defined.
gwen> When I complete each open item

Moving onto the third step:

And I clear all completed items

We don’t need to define a new step definition for this one because we already have it defined in the original meta we started with. If you still have the REPL session open, you can type the above step directly into the REPL and it will execute. In case you missed the step definition for this, here it is below:

@StepDef
Scenario: I clear all completed items
     When I click the clear completed button

Now we just need to add the following step definition for the final step in our scenario. The meta entry for that follows:

@StepDef 
Scenario: I should have no items left
     Then the number of open items should not be displayed

We have now completed defining all the step definitions we need. Exit the currently open REPL session if you have it open and run the following command to execute our new feature spec:

Linux/Mac/PowerShell:

./gwen -b samples/todo/wip/Todo.feature

Windows DOS:

gwen -b samples/todo/wip/Todo.feature

That’s it. We’re done!

We have successfully refactored our executable specification and reduced it to a single scenario without all the redundancy we had before. Since this scenario is also self contained, we can execute it in parallel with any other scenarios that we might add to the feature later.

Open the report at gwen-workspace/target/reports to see the results.

Click on each step in the report to drill down into the step definition.

Published by

Branko Juric

Imperative by day and functional by night. Co author of the Gwen automation platform.

2 thoughts on “Refactoring executable Gherkin with Gwen to eliminate redundancy”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s