Thursday, August 2, 2018

Parameterization in Cucumber - Bean Objects

Another way to pass data table is through data table transformer to convert the data table to a list of bean object. You don't need to define data entry transformer in the previous version of Cucumber 3.0. But you have to do that if you use the latest version of Cucumber.

Here is the feature definition.

  Scenario: Login Failure
    Given User is on Home Page
    And Sign In link is displayed
    When User clicks the Sign In link
    And User enters Credentials to login
    | Username | Password|
    | username | password|
    | username1 | password1|
    Then User should be login failed message

And Bean definition.

package me.simplejavautomation.data;

public class Credentials {

    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}


Define and register table transformer.

package me.simplejavautomation.data.transformer;

import java.util.Locale;
import java.util.Map;

import cucumber.api.TypeRegistry;
import cucumber.api.TypeRegistryConfigurer;
import io.cucumber.datatable.DataTableType;
import io.cucumber.datatable.TableEntryTransformer;
import me.simplejavautomation.data.Credentials;

public class TypeRegistryConfiguration implements TypeRegistryConfigurer {

    @Override
    public Locale locale() {
        return Locale.ENGLISH;
    }

    @Override
    public void configureTypeRegistry(TypeRegistry typeRegistry) {
        typeRegistry.defineDataTableType(new DataTableType(Credentials.class,
                  new TableEntryTransformer<Credentials>() {

            @Override
            public Credentials transform(Map<String, String> entry)
                   throws Throwable {
                Credentials credentials = new Credentials();
                credentials.setUsername(entry.get("Username"));
                credentials.setPassword(entry.get("Password"));
                return credentials;
            }
        }));
    }
}


Add transformer package to CucumberOptions configuration

package me.simplejavautomation;

import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/features",
       glue = { "me.simplejavautomation.stepdefs",
        "me.simplejavautomation.data.transformer" })
public class CucumberTestRunner {

}

And then you are ready to go.

Parameterization in Cucumber - Data Tables

To pass a group of data to a single feature step, you can use Data Tables in Cucumber feature definition.

Scenario: Successful Login with Valid Credentials
    Given User is on Home Page
    When User Navigate to LogIn Page
    And User enters Credentials to LogIn
        | user1 | p2ssword |
        | user2 | p2ssword |
    Then Message displayed Login Successfully

Just use "|" mark to separate different column and each line as a table row.

@When("^User enters Credentials to LogIn$")
public void user_enters_credentials_to_login(DataTable credentials) {
    List<List<String>> data = credentials.asLists();
    driver.findElement(By.id("xv_username")).sendKeys(data.get(0).get(0));
    driver.findElement(By.id("header-myairnz-password")).sendKeys(data.get(0).get(1));
    driver.findElement(By.cssSelector("input[name='login']")).click();
}

When it is passed to step definition method at runtime, you may access this data table through DataTable parameter.


1) Data tables as List<List<String>>
     You can call "credentials.asLists();" to get a List<List<String>> object to access all the data in the data table, just like a two dimension array.

2) Data tables as List<Map<String, String>>
    Or you can call "credentials.asMaps() to get a List<Map<String, String>> object to access all the data in the data table, but make sure you have added a key row in the first row in the data table.

     | Username| Password|
     | user1 | p2ssword |
     | user2 | p2ssword |

    To access Map list,

List<Map<String, String>> data =  dataTable.asMaps();
username = data.get(0).get("Username");
password = data.get(0).get("Password");

Check the other interface in DataTable, you can find other ways you wanted.

Wednesday, August 1, 2018

Parameterization in Cucumber - Examples

Another way to pass test input to step definition method is using Examples keyword in Scenario Outline.


  Feature: Sign In

  Scenario Outline: Login Failure
    Given User is on Home Page
    And Sign In link is displayed
    When User clicks the Sign In link
    And User enters wrong "<username>" and "<password>"
    Then User should be login failed message

  Examples:
      | username  | password  |
      | username1 | password1 |
      | username2 | password2 |


The Cucumber runner will execute all the inputs in Examples table one by one in while scenario steps.

The step definition is the same as the last post.

Parameterization in Cucumber - Quotation

When feature step has been glued to step definition, there are several ways to pass parameters to step definition from features.

The first way is using quotation marks ("") in features.

  Feature: Sign In

  Scenario: Login Failure
    Given User is on Home Page
    And Sign In link is displayed
    When User clicks the Sign In link
    And User enters wrong "username" and "password"
    Then User should see the failed message


So the "username" and "password" will be passed to step definition method as parameters.

@When("User enters wrong \"(.*)\" and \"(.*)\"")
public void user_enters_wrong_username_and_password(String username, String password) {
...
}

Cucumber Options

To execute the Cucumber test, you have to configure features and glue to Cucumber runner.

package me.simplejavautomation;

import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/features",
    glue = { "me.simplejavautomation.stepdefs"})
public class CucumberTestRunner {

}

Here is the diagram of CucumberOptions annotation.

dryRun -- show steps if don't have step definition.
features -- the paths of feature files.
glue -- the classpath of step definition files.
tags -- specify which tags in feature files should be executed.
monochrome -- display console output in the much readable way.
plugin -- specify different formatting options for the output reports.
strict -- if strict mode is enabled (fail if there are undefined or pending steps).
name -- specify a pattern filter for features or scenarios
snippets -- what format should the snippets use. underscore, camelcase.
junit -- the options for the JUnit runner.

Tuesday, July 31, 2018

About Gherkin Keywords

Gherkin is a structured natural language that is used by business analysts to specify how they want the system to behave for given scenarios. The Gherkin language is simple.  It uses about 10 keywords (Given, When, Then, And, But, Scenario, Feature, Background, Scenario Outline, Examples) which allow the language to be read and parsed by an automation tool called Cucumber. Here is an example:

Feature: Some terse yet descriptive text of what is desired
  In order to realize a named business value
  As an explicit system actor
  I want to gain some beneficial outcome which furthers the goal

  Scenario: Some determinable business situation
    Given some precondition
      And some other precondition
     When some action by the actor
      And some other action
      And yet another action
     Then some testable outcome is achieved
      And something else we can check happens too


Gherkin has a few high-level benefits:

1) Business Friendly Language: Gherkin is a simple to understand language using a limited number of keywords.  It's simplicity and natural style make it easy for business people to read and understand.

2) Requirement Traceability: It's used to write acceptance tests with a focus on system behavior.  Each acceptance test links to a scenario and feature which allows it to be traced back to the original requirements.  This is particularly evident with Agile methods that use short user stories combined with acceptance tests to define the requirements.

3) Test Automation: As a structured language using keywords, Gherkins is machine readable with the automation tool called Cucumber.  Developers write executable code for each step of the Gherkin acceptance test resulting in fully automated test scenarios.

4) Team Communication: With such a strong focus on defining acceptance tests business analyst, QA, and developers find themselves working more closely together to define, build, and test their applications.  The Gherkin acceptance test becomes a powerful and precise communication tool.

Here is the list of keywords that Gherkin supports:

  • Feature - List of scenarios.
  • Background - List of steps run before each of the scenarios
  • Scenario - Business rules through the list of steps with arguments.
  • Given - Some precondition step
  • When - Some key actions
  • Then - To observe outcomes or validation
  • And - To enumerate more Given, When, Then steps
  • But - To enumerate more Given, When, Then steps
  • Examples - Container for s table
  • * - replacement of all other step/blue keys

First Example of Cucumber

This is a simple example of showing how the Cucumber framework works.

To run Cucumber test, we need to define a Cucumber runner using @RunWith annotation.

package me.simplejavautomation;

import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/features",
    glue = { "me.simplejavautomation.stepdefs" })
public class CucumberTestRunner {

}

Cucumber.class is derived from JUnit runner. There are two attributes you need to define in CucumberOptions. One is 'features' to let Cucumber runner know where features are, it's the directory path of features. Another one is 'glue' to let Cucumber know where your Step Definitions are, it's the java package.

Second is to define features using Gherkin. It's a text file with .feature as the extension, and store in your features directory.

  Feature: Sign In

  Scenario: Login Failure
    Given User is on Home Page
    And Sign In link is displayed
    When User clicks the Sign In link
    And User enters wrong "username" and "password"
    Then User should see the failed message


The third is to define the step definition which is the glue between features and Java functions.

package me.simplejavautomation.stepdefs;

import static org.junit.Assert.assertEquals;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class SignInSteps {

    private WebDriver driver;

    @Given("User is on Home Page")
    public void user_is_on_Home_Page() {
        driver = new ChromeDriver();
        driver.get("https://www.airnewzealand.co.nz/");
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    }

    @Given("Sign In link is displayed")
    public void sign_In_link_is_displayed() {

    }

    @When("User clicks the Sign In link")
    public void user_clicks_the_Sign_In_link() {
        driver.findElement(By.id("login-button")).click();
    }

    @When("User enters wrong username\"(.*)\" and password\"(.*)\"")
    public void user_enters_wrong_username_and_password(String username, String password) {
        driver.findElement(By.id("xv_username")).sendKeys(username);
        driver.findElement(By.id("header-myairnz-password")).sendKeys(password);
        driver.findElement(By.cssSelector("input[name='login']")).click();
    }

    @Then("User should see the failed message")
    public void user_should_see_the_failed_message() {
        String alertMessage = driver.findElement(By.cssSelector("div[class='airnz-Alert__message']"))
                .findElement(By.xpath(".//p")).getText();
        assertEquals("To sign in to our website you now need to be ...", alertMessage);
    }

}

After you have done this, just simply execute JUnit Test under CucumberTestRunner class in your eclipse. You will see that it will follow the steps defined in features and execute them one by one.