All about Cucumber for Selenium

selenium-and-cucumber

There is a term Behavior Driven Development (BDD) (Read more),

Cucumber is framework which facilitate BDD in your development environment.

In most of the software organization there are various collaborative groups, we as a tester comes in technology group, which closely work with various software technologies and understand most of the software terminologies.

But there are many group which are closely working with business, and may not have much insight of software technology/terminology in spite of that most of the software development requirements come from this group.

Those requirements are basically the required behavior of the software which they describe in the form of various business scenarios.

Consider you are assigned to create Funds Transfer module in a Net Banking application.

There may below scenarios to develop/Test

  • Fund Transfer should take place if there is enough balance in source account
  • Fund Transfer should take place if the destination a/c details are correct
  • Fund Transfer should take place if transaction password / rsa code / security authentication for the transaction entered by user us correct
  • Fund Transfer should take place even if it’s a Bank Holiday
  • Fund Transfer should take place on a future date as set by the account holder

Now technology team would start to code to fulfill the scenarios, and we as a tester, test it against given scenarios and further automate those with various tools like selenium.

If we code our test in TestNG like frameworks, we could have many tests, and respective results for those test.

But here we miss the mapping of the business scenarios and automated test.

OK if I could create some document to map tests with scenarios it would be extra activity and having chances to miss some of them as we always do 🙂

Here comes Cucumber, which helps you to write Scenario in plain formatted English and bind them to your automated tests.

Cucumber provides you way to write you business scenarios in standard format as below

Given I am accessing it with proper authentication
When I shall transfer with enough balance in my source account
Or I shall transfer on a Bank Holiday
Or I shall transfer on a future date
And destination a/c details are correct
And transaction password/rsa code / security authentication for the transaction is correct
And press or click send button
Then amount must be transferred
And the event will be logged in log file

isn’t is more meaningful and easy to read and understand? it is as good as writing document for the given module.

Let’s start to implement Cucumber for our Selenium based tests.

  • Create a Maven Project.
  • add below dependencies in you pom.xml
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>RELEASE</version>
</dependency>

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-java</artifactId>
    <version>RELEASE</version>
</dependency>
<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-junit</artifactId>
    <version>RELEASE</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>RELEASE</version>
</dependency>

Now lets start the actual coding,

To make it simple add 2 separate packages in our source, one for Cucumber scenarios and other for Java bindings for scenarios.

Bindings for Cucumber scenarios are also called as Glue Code as it works as glue in between your Software Automation & English like Scenarios

Lets write a scenario for login the application http://seleniumbyneeds.github.io/resources/e2

Create file “LoginFeature.feature” in package “scenarios” and add below lines in the file.

Feature: Login feature

Scenario: Verify Login feature with valid credentials
Given I have opened an url "http://seleniumbyneeds.github.io/resources/e2/" in browser
When I shall enter "admin" in username filed
And I Shall enter "pa$$w0rd" in password field
And click on Login button
Then I should be logged in to application

As scenario is itself descriptive enough to understand, here we are fetching the url and adding username & password to login.

Let’s create glue-code for this feature. add “LoginFeature.java” class in package “glue”. add below code in the file. please change the package name as per your project setup.


import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

import java.util.concurrent.TimeUnit;

public class LoginFeature {
    WebDriver driver;
    @Given("I have opened an url {string} in browser")
    public void iHaveOpenedAnUrlInBrowser(String url) {
// running the test in chrome browser, you can choose your favorite or required
        System.setProperty("webdriver.chrome.driver","");
        driver = new ChromeDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.get(url);
    }

    @When("I shall enter {string} in username filed")
    public void iShallEnterInUsernameFiled(String userName) {
        driver.findElement(By.xpath("//input[@id='user']")).sendKeys(userName);
    }

    @And("I Shall enter {string} in password field")
    public void iShallEnterInPasswordField(String password) {
        driver.findElement(By.xpath("//input[@id='password']")).sendKeys(password);
    }

    @And("click on Login button")
    public void clickOnLoginButton() {
        driver.findElement(By.xpath("//input[@id='login']")).click();
    }

    @Then("I should be logged in to application")
    public void iShouldBeLoggedInToApplication() {
        if(driver.findElements(By.xpath("//a[@id='logoutLink']")).size()==0){
            Assert.fail("not logged in");
        }
    }
}

We are almost done… only thing remain is to add a runner class as Cucumber needs Junit runner to run the scenarios/Scenario.

Add class name “Runner.java” and add below code in that.

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class )
@CucumberOptions(features = "src\\test\\java\\features",
        glue = "glue")
public class CucumberRunner {
}

now run the above test runner file. it will run your feature and show results on a console.

You can pass various option in @CucumberOptions as per you requirement. below are some of the important options.

Pretty:

it helps to create various report for the cucumber features, in below example it will create HTML report at given location


@CucumberOptions(
features = "src\\test\\java\\features",
glue = {"glue"},
plugin = { "pretty", "html:target/cucumber-reports" },
)

This will generate an HTML report at the location mentioned in the option

cucmberfiles

HTML Report:

cucmberreport

You can also generate JSON or JUNIT xml report by adding option in cucumber options

Or you can generate all report all together

@CucumberOptions(
 features = "src/test/resources/functionalTests",
 glue= {"stepDefinitions"},
 plugin = { "pretty", "json:target/cucumber-reports/Cucumber.json",
 "junit:target/cucumber-reports/Cucumber.xml",
 "html:target/cucumber-reports"}
)

There are still many options features available in cucumber framework. I will try to write on some in coming blog-posts.

Till that time keep Automating……….

Advertisements

Wait for Pop-up

popup In recent past, I encountered one scenario where you need to automate pop-up in the application. I am blogging this, as many of you may have faced the same issue.

You need to automate the below scenario. There is a link present on the Web-page, Pop-up gets opened as you click on the link & perform some action on this pop-up.

Now you may wonder what’s the big deal in just automating above scenario.

I also thought in the same way but my scripts were failing.

After investigation I found that when I tried to switch to pop up it was not there,meaning till that time pop up didn’t get open.

I tried to apply Thread.Sleep ,it worked fine for me. But again using Thread.Sleep can cause many issues like –

  1. This may fail if opening a pop up takes longer time
  2. If pop up gets open up in fraction of seconds then it will be waste of time.
  3. It is not the good practice to use Thread.Sleep and be last option we should think of when synchronize the browser.

There is no direct solution or Expected condition available in Selenium WebDriver for this issue. Hence to overcome all these problems I have written a method which implements new Expected condition and exactly behaves like implicit wait.

private void clickWaitForPopoUp(WebDriver driver, By by,int waitTime) {
        final int currentWindows = driver.getWindowHandles().size();
        driver.findElement(by).click();
        WebDriverWait wait = new WebDriverWait(driver, waitTime);
        wait.until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver d) {
                return (d.getWindowHandles().size() != currentWindows);
            }
        });
    }