Cucumber Feature File Step Definition

Reading Time 9 minutes

Following on from my previous tutorial where we installed Cucumber in this tutorial we will cover the basics of Cucumber Feature File and start writing our first Step Definition class in Java.

01 Cucumber Feature File

What is a Cucumber Feature File? A Feature File in Cucumber is a simple text file that represents test scenarios. It showcases scenarios to be tested using a very structured plain text language called Gherkin. When expressing a scenario using the following keywords ‘Given’, ‘When’ and ‘Then’, these keywords can be used to very easily express some condition, an action to be take against that condition and the expected result of that action. For instance:

Given I navigate to TheTestRoom.com
When I navigate to Cucumber Tutorial page
Then the page title should be visible

Using ‘Given’, ‘When’ and ‘Then’ to express a scenario makes it very easy to understand what it is that your trying to do. This type of wording or plain text language is called Gherkin.

A basic Cucumber Feature File also consists of two other parts and these are the ‘Feature’ and ‘Scenario’ sections. The Feature section is used only for description purposes. It is used to tell the reader the types of tests that the Feature file contains. Once happy with the ‘Feature’ section of your Cucumber File we can then declare some ‘Scenario’ sections. The ‘Scenario’ sections essentially outline the actual tests. A Cucumber Feature File contains a ‘Feature’ and one or more ‘Scenario’ sections such as this:

Feature: To check that main tutorial course pages have loaded in TheTestRoom.com

Scenario: To check that the WebDriver Cucumber tutorial main page has loaded
Given I navigate to TheTestRoom.com
When I navigate to Cucumber Tutorial page
Then the page title should be visible

Features and scenarios make up the construct of a Cucumber Feature File.

02 Running our Cucumber Feature File

If you don’t know how to run a Feature file then read my previous tutorial first before proceeding any further.

Now lets go ahead and run our Feature File.

java -cp "jars/*" cucumber.api.cli.Main -p pretty features

When we run the above Feature file we get the following output:

Feature: To check that main tutorial course pages have loaded in TheTestRoom.com

Scenario: To check that the WebDriver Cucumber tutorial main page has loaded # myFirstFeature.feature:3
Given I navigate to TheTestRoom.com
When I navigate to Cucumber Tutorial page
Then the page title should be visible

1 Scenarios (1 undefined)
3 Steps (3 undefined)
0m0.000s

You can implement missing steps with the snippets below:

@Given("^I navigate to TheTestRoom\\.com$")
public void i_navigate_to_TheTestRoom_com() throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
@When("^I navigate to Cucumber Tutorial page$")
public void i_navigate_to_Cucumber_Tutorial_page() throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
@Then("^the page title should be visible$")
public void the_page_title_should_be_visible() throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

Lets see what is going on above. Firstly Cucumber was able to identify our Cucumber Feature File and each test step that we have written. However if you look further down it is not very happy about the steps as it says that the scenarios are ‘undefined’ as well as the test steps, what does this mean? When Cucumber says that something is undefined then this means that Cucumber was not able to find the relevant code snippets for the test steps in a Feature File. What this means is that every time Cucumber runs a Feature File it tries to look for a matching ‘Step Definition’ for a Gherking test. In this instance Cucumber is returning ‘undefined’ for all three test steps as they have not been defined anywhere. This means our next natural step is to try and write code for these test steps.

03 Writing our First Step Definition

Before writing our step definition lets take another quick look at the output from the Feature File:

.....
.....
.....
@Given("^I navigate to TheTestRoom\\.com$")
public void i_navigate_to_TheTestRoom_com() throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
@When("^I navigate to Cucumber Tutorial page$")
public void i_navigate_to_Cucumber_Tutorial_page() throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
@Then("^the page title should be visible$")
public void the_page_title_should_be_visible() throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

Cucumber can actually be very helpful. The above code is something that Cucumber has generated for us when it tried to find a match for each test step. Each code snippet generated above is called a ‘Step Definition’. We won’t go into too much detail about step definitions now as we will continuously visit them over this entire tutorial course but for now lets copy them into a Java class and place this class in our project folder:

cd cucumber_project
mkdir step_definition
touch myFirstStepDefinition.java

Now lets VIM into the step definition class and copy in the generated step definitions as well as importing in the jars for Cucumber. Let’s also name the package to match the folder name in which the Java class is contained:

package step_definition;

import cucumber.api.java.en.*;
import cucumber.api.PendingException;

public class myFirstStepDefinition {

        @Given("^I navigate to TheTestRoom\\ .com$")
        public void i_navigate_to_TheTestRoom_com() throws Throwable {
                // Write code here that turns the phrase above into concrete actions
                throw new PendingException();
        }
        @When("^I navigate to Cucumber Tutorial page$")
        public void i_navigate_to_Cucumber_Tutorial_page() throws Throwable {
                // Write code here that turns the phrase above into concrete actions
                throw new PendingException();
        }
        @Then("^the page title should be visible$")
        public void the_page_title_should_be_visible() throws Throwable {
                // Write code here that turns the phrase above into concrete actions
                throw new PendingException();
        }
}

We now need to compile the Java class:

javac "jars/*" step_definition/myFirstStepDefinition.java

Lets try to run our Feature File but also provide a ‘glue’ reference to where the ‘Step Definition’ class is:

java "jars/*;." cucumber.api.cli.Main -p pretty -g step_definition features

So what is happening? Firstly we appended the current directory to the jars with ‘.’ and then supply a reference to where the ‘Step Definition’ classes are via the ‘-g’ parameter. If done correctly then you will get an output similar to the below:

Feature: To check that main tutorial course pages have loaded in TheTestRoom.com

  Scenario: To check that the WebDriver Cucumber tutorial main page has loaded # myFirstFeature.feature:3
    Given I navigate to TheTestRoom.com                                         # myFirstStepDefinition.i_navigate_to_TheTestRoom_com()
      cucumber.api.PendingException: TODO: implement me
        at step_definition.myFirstStepDefinition.i_navigate_to_TheTestRoom_com(myFirstStepDefinition.java:11)
        at ?.Given I navigate to TheTestRoom.com(myFirstFeature.feature:4)

    When I navigate to Cucumber Tutorial page                                   # myFirstStepDefinition.i_navigate_to_Cucumber_Tutorial_page()
    Then the page title should be visible                                       # myFirstStepDefinition.the_page_title_should_be_visible()
1 Scenarios (1 pending)
3 Steps (2 skipped, 1 pending)
0m0.122s

cucumber.api.PendingException: TODO: implement me
        at step_definition.myFirstStepDefinition.i_navigate_to_TheTestRoom_com(myFirstStepDefinition.java:11)
        at ?.Given I navigate to TheTestRoom.com(myFirstFeature.feature:4)

Right, now we are getting somewhere. The output confirms that Cucumber was able to match the first test step in our Feature File to a step definition in our ‘Step Definition’ class. The glue reference in Cucumber is used to help Cucumber identify where to look for when trying to match code to test steps in Feature Files. That’s great.

When analyzing the output above we can see that 2 steps have been skipped and 1 was pending. That is because our steps in our Java code are currently throwing errors as that was what we pasted in i.e. the thrown Pending Exceptions. We now need to revisit our code and change them to do something a little more meaningful and not throw exceptions. Lets chance our code to the following:

vi step_definition/myFirstStepDefinition.java

And let’s update your Step Definition class to use print statements:

package step_definition;

import cucumber.api.java.en.*;

public class myFirstStepDefinition {

        @Given("^I navigate to TheTestRoom\\ .com$")
        public void i_navigate_to_TheTestRoom_com() throws Throwable {
                System.out.println( "Going to TheTestRoom.com" );
        }

        @When("^I navigate to Cucumber Tutorial page$")
        public void i_navigate_to_Cucumber_Tutorial_page() throws Throwable {
                System.out.println( "Clicking on Cucumber Tutorial Page" );
        }

        @Then("^the page title should be visible$")
        public void the_page_title_should_be_visible() throws Throwable {
                System.out.println( "Checking page title");
        }

}

As you can see our code is now a little more simplifier as all we are doing now is printing statements for each step definition code. Lets compile and run our Feature file:

javac -cp "jars/*" step_definition/myFirstStepDefinition.java
java -cp "jars/*;." cucumber.api.cli.Main -p pretty -g step_definition/ features/

And your output should now look like this:

Feature: To check that main tutorial course pages have loaded in TheTestRoom.com
Going to TheTestRoom.com
Clicking on Cucumber Tutorial Page
Checking page title

Scenario: To check that the WebDriver Cucumber tutorial main page has loaded # myFirstFeature.feature:3
Given I navigate to TheTestRoom.com                                         # myFirstStepDefinition.i_navigate_to_TheTestRoom_com()
When I navigate to Cucumber Tutorial page                                   # myFirstStepDefinition.i_navigate_to_Cucumber_Tutorial_page()
Then the page title should be visible                                       # myFirstStepDefinition.the_page_title_should_be_visible()

1 Scenarios (1 passed)
3 Steps (3 passed)
0m0.113s

And thats it. You can now see that when we run our Feature file Cucumber is able to glue each test step in our Feature File to our Step Definition class and print out the statements which we supplied in our code. When each step definition code passes then Cucumber runs each step one after the other.

Now you should be much more comfortable understanding how Cucumber is able to match test steps in Feature files with code in Step Definition classes. In this tutorial we have discovered how Cucumber glues each test step to step definition code.

Video Tutorial on YouTube

cucumber feature file

Direct Video Link

Mo

I am a passionate tester, father, husband and gamer. I love to write blogs about Software Testing and generally contribute back to the Software Testing world.

More Posts - Twitter - Facebook

Published by

Mo

I am a passionate tester, father, husband and gamer. I love to write blogs about Software Testing and generally contribute back to the Software Testing world.

  • Pozhil

    Feature file not recognize JavaScript file, I’m getting undefined steps,scenario as output. can you give solution for this.

    • Mo

      Hi Pozhil,

      This is most likely because your Feature file is not able to find your step definition class? I would recommend that you copy paste the suggested step definition methods which the compilers provides. Copy in the method in a class and ensure to have the class in the same directory as your feature file.

      This should hopefully resolve your issue, let me know how you get on.

      Best,
      Shahin