Cucumber 101

My primary reason for using Cucumber in a recent automation initiative was to try and bridge a technology-business divide that existed in my workplace by giving the non-technical stakeholders a larger sense of involvement in testing with a (longer term) view to them actively contributing to future test specs by using the plain English approach that Cucumber does so well.

However, when I first started looking into Cucumber, there were a multitude of references out there but as I was also learning about Ruby, Watir and RSpec at the same time it became a little difficult to see the wood for the trees because they tended to talk about all of these things without being clear about where one thing stopped and another began.

What I’d like to do with this post is present a simple Cucumber 101 tutorial, letting cucumber guide us through the creation of a set of ‘scenarios’  (this is what Cucumber calls ‘tests’ or to be more precise, ‘checks’ – this is automated after all).

1. Cucumber Basics

Cucumber is a command line tool and when you run it, it looks for plain-language text files which typically contain one or more features, and within each feature, one or more scenarios to test. Within each scenario you have a number of steps that Cucumber works through. There is some syntax involved so that cucumber can understand what you’ve written and this is known as Gherkin. I’ll highlight this in the examples below.

cuke-stack

So if you were to see the directory structure required for a simple cucumber project, it would look something like this:

cuke-01

2. Installation Prerequisites

This tutorial assumes you have a copy of ruby, rubygems (or equivalent), watir-webdriver, rspec and of course cucumber installed on your target system.

3. Create a Scenario

Let’s create a new Cucumber project (a directory, called ‘Cuke’) and try running cucumber in this empty directory.

Wait, how do we run cucumber? Simple, type ‘cucumber’ (Note: We can specify arguments but in the absence of any cucumber assumes you want to run everything – more on that later).

cuke-02

So we have no features or scenarios. Cucumber is looking for a features directory. Let’s create one as it suggests. Once we’ve done that, let’s try running cucumber again.

cuke-03

So now we see that although cucumber found a features directory, there were no feature files and consequently no scenarios to run, hence the “0 scenarios” and “0 steps” references.

Let’s create a scenario in a feature file under the features directory, and let’s call the feature file karate.feature. Here’s the content:

cuke-04

For those of you unfamiliar with karate, Hironori Ohtsuka was the founder of the Wado-Ryu style of karate, and our scenario is checking for the presence of the founder’s surname in the Google results on a search for ‘Wado’.

You can see the Gherkin grammar highlighted in blue above – these must be used when writing feature files – the key Gherkin words include – Feature, Background, Scenario, Scenario Outline, Scenarios (or Examples), Given, When, Then, And (or But) and a couple of other symbols.

Now let’s run cucumber again with the new feature file in place:

cuke-05

So, cucumber is now picking up our new feature file. Great!

However, all of our scenario steps are as yet undefined.

4. Add Step Definitions

So, two things about the above output. Cucumber is telling us that our steps and scenario are as yet undefined (the yellow text) and that as yet, it doesn’t know which programming language we intend to use to implement our scenarios (the red text). Let’s take our lead from Cucumber and copy the suggested steps into a new step definition file, say step_karate.rb (The .rb suffix indicates a Ruby file). Like so…

cuke-06

and run cucumber again

cuke-07

You may notice that the red text we saw in the ‘undefined’ error above has now gone. Why? We’ve put a Ruby (.rb) step definition file in place so Cucumber now knows we’re intending to use ruby to implement the scenario. So now we can map all the steps in our scenario to a step definition file, and cucumber helpfully provides the file and line number of each step it finds (this comes in useful later when you have large suites of scenarios) You’ll also notice that Cucumber has deemed the first step as ‘pending‘ (I.e. to be implemented) – this is due to the pending statement in the step definition. This acts as a placeholder so you can write some proper code for each step when you are ready. Cucumber takes a sequential approach to scenario steps and the subsequent steps are deemed ‘skipped

5. Implement Step Definitions

Let’s implement our first step definition now. We’ll take out the pending statement and put in some Ruby code that will start a web-browser.

cuke-08

So for our first step “I navigate to Google” we’ve removed the pending statement and inserted two lines of Ruby/Watir-Webdriver, to start a browser (Firefox) and to navigate to Google.

Note: I’ve included a Ruby ‘require’ statement in the step definition file. There are tidier ways of doing this since the key to maintainability of any cucumber suite lies with the step definition files. We’ll tidy this up a bit later

Let’s run cucumber again

cuke-09

Now we see the first step passes (green), the second step is pending (yellow), and the third step is skipped (blue). Progress! You’ll also notice a browser opened in front of you (at Google) that hasn’t been closed – that’s because we didn’t close it in our code (yet). For now, kill the browser – we’ll tidy that up later. Let’s implement the remaining steps as shown below:

cuke-10

In the second step, we create variables for the Google search field and button, then enter the value ‘Wado’ into the search field and click on the button. In the third step we check that the results page has loaded and then perform another check to see if the text  ‘Ohtsuka’ is present in the results page. If it’s there, the step will pass, and if it’s not the step will fail. Lastly, we close the browser instance.

6. Passed & Failed Scenarios

So, if we run cucumber once again with all our implemented steps:
cuke-11
Whoa! 3 passed steps and 1 passed  scenario. Nice!
However, in order to see what a failed scenario looks like, let’s deliberately alter the string literal in the last step  ‘Ohtsuka’ to ‘Octavias’ as we don’t expect that to appear in the page, and run cucumber again:
cuke-12
So you can see from the above the scenario has now failed after being unable to locate ‘Octavias’ in the results page. If you run this you’ll notice that the browser stayed open which means the @browser.close statement was never executed. Hmm, messy. Let’s tidy this up a bit…

7. Tidy Up – Environment, Hooks, etc

First of all, let’s get rid of that ‘require’ statement in the step definition file and put it somewhere more appropriate. We’ll create a new directory under features, called support, and under there we’ll create an environment file, env.rb and add two lines

cuke-13
The first line extends the path that Cucumber picks up to include a Cuke/lib (we haven’t created that yet)
The second line includes a Ruby file called myClasses.rb (we haven’t created that either)
Let’s create those too.
cuke-14
So our require watir-webdriver statement lives here, we can remove it from step_karate.rb
Next, let’s add another file to the support subdirectory, called hooks.rb and use the Before and After methods to define actions that should be taken before and after each and every scenario. Like, starting up and closing down a browser.
cuke-15
Now we can remove those statements from step_karate.rb as well.
If we re-run the scenario this time, it will still fail but the browser will be closed down regardless of the outcome.

8. HTML Formatters

You can also direct cucumber output to  an HTML file using the default HTML formatters. by running the command:

cucumber -f html >output.html

The contents of output.html then look like this:
cuke-16

So as you can see the failed step is highlighted in red, as is the scenario, as is the cucumber header (if one scenario out of many fail then the header is coloured red accordingly).

Now let’s change the string ‘Octavias’ back to ‘Ohtsuka’ and re-run

cuke-17

The Scenario headers in these HTML files can be collapsed or expanded individually (left click on it) or along with everything else in the page (use ‘Collapse All’/’Expand All’ in the header)

9. Multiple (Similar) Scenarios – Placeholders

So our scenario checks the presence of the karate founder’s surname in the results when we search for the style name. What if we wanted to run a similar scenario for other styles of karate, say:
  • Wado-Ryu (Hironori Ohtsuka)
  • Shotokan (Gichin Funakoshi)
  • Goju-Ryu (Chojun Miyagi)
  • Kyokushinkai (Masutatsu Oyama)
We could of course write separate scenarios and create new step definitions (primarily for steps 2  and 3, step 1 could be reused). The trouble there is that when you have a lot of scenarios which do the same thing with different arguments, it becomes laborious to wade through the results and difficult to see the uniqueness of each scenario.
So let’s consider refactoring our scenario to become a scenario outline – that way we only have to specify our steps once, and use placeholders to identify the unique values we wish to use within each iteration. Here’s what the refactored feature file looks like:
cuke-18
So the placeholders are the elements in the angled brackets in the steps, <karateStyle> and <masterSurname>. The Examples section (Note, you could also use the text ‘Scenarios:’ here instead of ‘Examples:’) is simply a table with the placeholder names (minus the angled brackets) as headers and the values you wish to use below them.
The scenario outline is useless without the examples and the four examples now constitute a single scenario.
Let’s take a look at the refactored step definition file:
cuke-19
The (\w+) elements are shorthand character classes and stand for a word character, specifically [A-Za-z0-9]. The value is read into the variable (karate or surname) which we can then use in place of the string literals (‘Wado’ and ‘Ohtsuka’) we had previously.

10. Tagging

Tagging is easily one of the most powerful aspects of cucumber and for me, the thing that made it so versatile when dealing with a large number of scenarios. A tag in cucumber is simply a text string preceded by the ampersand character, and we generally use them in the feature file by placing them before Gherkin keywords such as Scenario Outline, Scenarios, Examples, etc. You can have more than one tag for the same scenario, just separate them with spaces.
Tags can represent anything that’s meaningful to you – the name of the scenarios (e.g. @scenario1, @scenario2, etc.) , the performance of the scenarios (e.g. @quick, @slow, @glacial), the frequency of the scenarios (e.g. @hourly, @daily, @weekly, etc.) – anything that makes it easier to slice and dice your scenarios into meaningful cross-sections that make execution a breeze.
Let’s refactor our feature file with some tags:
cuke-20
We can run cucumber and pass in some arguments to tell it to run everything associated with a particular tag by using a command like

cucumber -t <tag>

where <tag> is the tag name. So in the case above if we ran:
  • cucumber -t @all  (This would run everything – all four scenarios)
  • cucumber -t @daily (This would run the top two scenarios for Wado and Shotokan)
  • cucumber -t @monthly (This would run the bottom two scenarios for Goju and Kyokushinkai)
  • cucumber -t @wado (This would only run the top scenarios for Wado)
You get the idea, right?
So there you go, 10 steps to cukey heaven. Enjoy…

  15 comments for “Cucumber 101

  1. 8th January, 2013 at 9:25 pm

    Thank you very much for sharing this. It is clear, concise and accurate, all the steps work perfectly. This has been a huge help in giving me a great starting point in using these tools. Thanks again, John.

  2. 8th March, 2013 at 3:43 pm

    Fantastic Tutorial. Thanks a lot for sharing this.

    Reading thru this I am automating the triangle exercise from Eusebiu Blindu @ http://test1.testalways.com/cgi-bin/triangle/TestTriangle.html, so I get better at all these tools ;). One question I had in mind is – I observe that the web driver launches firefox before running each test. Is it possible to launch the browser for the first and then run all the tests and close it at the end?

    Thanks
    Sharath

    • Del Dewar
      8th March, 2013 at 5:10 pm

      Hi Sharath,

      Thanks for the comments/feedback.

      Yes, it’s absolutely possible to run all of the above tests with a single browser instance but in my experience it’s wise to use a fresh browser instance for each test.
      One of the benefits of having a browser instance per test is that it encourages the re-use of the step definitions, helps minimise maintenance and arguably makes it easier to diagnose issues when they’re encountered (I.e. You know a problem falls within a specific test as opposed to trying to figure out whether it failed as a consequence of one of the many many earlier steps)

      Good luck
      Del.

      • 13th March, 2013 at 3:50 pm

        Yes that’s a very valid point.

        I think I am stuck at a point where cucumber keeps complaining about pending step defintion when I have a step definition defined for it. If you are free could you please help me with it?

        Thanks
        Sharath

      • Del Dewar
        14th March, 2013 at 7:29 pm

        Sure. PM me your email on twitter (@deefex) and I’ll try and help.

  3. Superkevy
    14th March, 2013 at 7:03 pm

    Greatest starting point document so far! Had to require rspec in the samples for “should” method.
    For WADO the search may fail to find expected match so I updated them to include Karate (i.e. Wado Karate).

    I see the browser open but unlike my standard watir-webdriver scripts I don’t see the navigation and actual form fills and submit results in the view. Maybe it just happens too fast to render completely.

  4. 27th July, 2013 at 12:55 pm

    I get this warning running cucumber with ruby 1.9.3
    *** WARNING: You must use ANSICON 1.31 or higher (https://github.com/adoxa/ansic
    on/) to get coloured output on Windows
    Hasn’t anybody encountered this issue?

  5. 15th August, 2013 at 1:44 am

    The example offered here doesn’t quite work because the search on ‘Wado’ does not produce a page with the text ‘Ohtsuka’ on it, I have tried to modify the step_karate.rb file as follows, but since I am new to Cucumber Ruby I can’t quite get this right (see error reporting below). Here is my intention:

    Given /^I navigate to Google$/ do
    @browser.goto “http://www.google.com.au”
    end

    When /^I enter (\w+) into the search field$/ do | karate |
    searchField = @browser.text_field(:name, ‘q’)
    searchButton = @browser.button(:name, ‘btnG’)
    searchField.set karate
    searchButton.click
    end

    Then /^a link to Wikipedia should be there$/ do
    link = @browser.link :text => ‘Wikipedia’
    link.exists?
    end

    When /^I click on the Wikipedia link$/ do
    link.click
    end

    Then /^the text (\w+) should be present$/ do | surname |
    @browser.div(:id => ‘resultStats’).wait_until_present
    (@browser.text.include? surname).should == true
    end

    ————————-
    This is what is reported when I run:

    E:\Ruby193\cuke>cucumber
    Feature: Traditional Karate

    Scenario Outline: Where is the Master? # features\karate.feature:3

    Given I navigate to Google # features/step_definitions
    /step_karate.rb:2
    When I enter into the search field # features/step_definitions
    /step_karate.rb:6
    Then a link to wikipedia should be there # features\karate.feature:6

    When I click on the Wikipedia link # features/step_definitions
    /step_karate.rb:18
    Then the text should be present # features\karate.feature:8

    Examples:
    | karateStyle | fullStylename |
    | Wado | Ohtsuka |

    1 scenario (1 undefined)
    5 steps (1 skipped, 2 undefined, 2 passed)
    0m7.664s

    You can implement step definitions for undefined steps with these snippets:

    Then(/^a link to wikipedia should be there$/) do
    pending # express the regexp above with the code you wish you had
    end

    Then(/^the text should be present$/) do
    pending # express the regexp above with the code you wish you had
    end

    ————————-
    I was hoping someone could perhaps explain how to get this modification to work.

    • Superkevy
      15th August, 2013 at 1:28 pm

      Update the input value kartateStyle ‘Wado’ to ‘Wado Karate’. That corrects the search results. Its an old script browser rankings change over time which is why its no longer in the top ten return results.

      • 16th August, 2013 at 3:44 am

        Sorry that doesn’t actually help – the search in my browser still fails.
        I have rejigged the scenario outline to try and make the result more resilient and not dependent on browser rankings.
        I am keen to get my Ruby code to work….

      • Del Dewar
        9th October, 2013 at 9:50 pm

        OK, I did a little tinkering and got something working.
        I used slightly modified scenario text so there wasn’t multiple when/thens but the gist is the same. Note – I had to change the angle brackets for the parameters in the feature file in this comment as wordpress kept removing them.

        feature file contents:
        Feature:Traditional Karate

        Scenario Outline:Where is the Master?

        Given I navigate to Google and search using the term [karateStyle]
        And the results include a Wikipedia link
        When I click on the Wikipedia link and view the page
        Then the [masterForename] should be present

        Examples:
        | karateStyle | masterForename |
        | Wado | Hironori |

        and the ruby step definition file contains:

        require ‘watir-webdriver’

        Given(/^I navigate to Google and search using the term (\w+)$/) do | karate |
        @browser = Watir::Browser.new :ff
        @browser.goto “http://www.google.com.au”
        searchField = @browser.text_field(:name, ‘q’)
        searchButton = @browser.button(:name, ‘btnG’)
        searchField.set karate
        searchButton.click
        end

        Given(/^the results include a Wikipedia link$/) do
        @browser.div(:id => ‘resultStats’).wait_until_present
        (@browser.text.include? ‘Wikipedia’).should == true
        end

        When(/^I click on the Wikipedia link and view the page$/) do
        wikiLink = @browser.a(:text,/.*Wikipedia.*/)
        @browser.goto wikiLink.href
        end

        Then(/^the (\w+) should be present$/) do | forename |
        @browser.div(:id => ‘mw-page-base’).wait_until_present
        (@browser.text.include? forename).should == true
        @browser.close
        end

        I had to change the surname to forename as there are some peculiarities with diacritics in the wiki version of the surname which I could probably get working with some more time, but it was easier to use the forename to illustrate the example.

        Enjoy.

  6. Nikita
    18th February, 2014 at 3:37 pm

    fantastic starting point! This is what you need, the books are fine but this is just a fantastic starting point and I would advise people learning Ruby and Cucumber to start here.

  7. Ruchi
    7th May, 2014 at 11:21 am

    Excellent work. It really helped me to get started with cucumber.Thanks

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 )

Facebook photo

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

Connecting to %s

%d bloggers like this: